diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToDoubleAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToDoubleAction.java index f3674c264f..82545588e9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToDoubleAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToDoubleAction.java @@ -42,7 +42,7 @@ public class ConvertToDoubleAction extends AbstractConvertAction { try { FloatFormat format = FloatFormatFactory.getFloatFormat(dataOrganization.getDoubleSize()); - return format.getHostFloat(s.getBigInteger()); + return format.round(format.getHostFloat(s.getBigInteger())); } catch (UnsupportedFloatFormatException e) { return null; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToFloatAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToFloatAction.java index d2dce5e735..63121d40e7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToFloatAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToFloatAction.java @@ -41,7 +41,7 @@ public class ConvertToFloatAction extends AbstractConvertAction { DataOrganization dataOrganization = program.getDataTypeManager().getDataOrganization(); try { FloatFormat format = FloatFormatFactory.getFloatFormat(dataOrganization.getFloatSize()); - return format.getHostFloat(s.getBigInteger()); + return format.round(format.getHostFloat(s.getBigInteger())); } catch (UnsupportedFloatFormatException e) { return null; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java index 5919bd2895..afbe5a3ab6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java @@ -18,8 +18,7 @@ package ghidra.test.processors.support; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.math.BigDecimal; -import java.math.BigInteger; +import java.math.*; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -255,8 +254,10 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E try { // By default, create test output within a directory at the same level as the // development repositories - outputRoot = - Application.getApplicationRootDirectory().getParentFile().getParentFile().getCanonicalPath(); + outputRoot = Application.getApplicationRootDirectory() + .getParentFile() + .getParentFile() + .getCanonicalPath(); } catch (IOException e) { throw new RuntimeException(e); @@ -761,15 +762,17 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E private static class FloatFormatter extends DumpFormatter { private final FloatFormat ff; + private final int maxWidth; FloatFormatter(int elementSize, boolean bigEndian) { super(elementSize, bigEndian); ff = FloatFormatFactory.getFloatFormat(elementSize); + maxWidth = ff.round(ff.maxValue).negate().toString().length(); } @Override int getMaxWidth() { - return ff.maxValue.negate().toString().length(); + return maxWidth; } @Override @@ -779,7 +782,7 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E false) : LittleEndianDataConverter.INSTANCE.getBigInteger(bytes, index, elementSize, false); - BigDecimal val = ff.getHostFloat(encoding); + BigDecimal val = ff.round(ff.getHostFloat(encoding)); return val.toString(); } } @@ -873,7 +876,8 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E String floatStr = ""; if (reg != null && floatRegSet.contains(reg)) { FloatFormat floatFormat = FloatFormatFactory.getFloatFormat(size); - BigDecimal hostFloat = floatFormat.getHostFloat(new BigInteger(1, values)); + BigDecimal hostFloat = + floatFormat.round(floatFormat.getHostFloat(new BigInteger(1, values))); floatStr = " (" + hostFloat.toString() + ")"; } @@ -1640,8 +1644,8 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E if (tReg != null && (offset & 1) == 1) { RegisterValue thumbMode = new RegisterValue(tReg, BigInteger.ONE); try { - program.getProgramContext().setRegisterValue(functionAddr, functionAddr, - thumbMode); + program.getProgramContext() + .setRegisterValue(functionAddr, functionAddr, thumbMode); } catch (ContextChangeException e) { throw new AssertException(e); @@ -1654,8 +1658,8 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E if (isaModeReg != null && (offset & 1) == 1) { RegisterValue thumbMode = new RegisterValue(isaModeReg, BigInteger.ONE); try { - program.getProgramContext().setRegisterValue(functionAddr, functionAddr, - thumbMode); + program.getProgramContext() + .setRegisterValue(functionAddr, functionAddr, thumbMode); } catch (ContextChangeException e) { throw new AssertException(e); @@ -1879,8 +1883,8 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E GZF_CACHEDIR_NAME + "/" + fileReferencePath + GZF_FILE_EXT; // if (absoluteGzfFilePath.exists()) { program = getGzfProgram(outputDir, gzfCachePath); - if (program != null && !MD5Utilities.getMD5Hash(testFile.file).equals( - program.getExecutableMD5())) { + if (program != null && !MD5Utilities.getMD5Hash(testFile.file) + .equals(program.getExecutableMD5())) { // remove obsolete GZF cache file env.release(program); program = null; @@ -1904,8 +1908,8 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E env.getGhidraProject().importProgram(testFile.file, loaderClass); } else { - program = env.getGhidraProject().importProgram(testFile.file, language, - compilerSpec); + program = env.getGhidraProject() + .importProgram(testFile.file, language, compilerSpec); } program.addConsumer(this); env.getGhidraProject().close(program); @@ -1925,8 +1929,9 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E txId = program.startTransaction("Analyze"); if (!program.getLanguageID().equals(language.getLanguageID()) || - !program.getCompilerSpec().getCompilerSpecID().equals( - compilerSpec.getCompilerSpecID())) { + !program.getCompilerSpec() + .getCompilerSpecID() + .equals(compilerSpec.getCompilerSpecID())) { throw new IOException((usingCachedGZF ? "Cached " : "") + "Program has incorrect language/compiler spec (" + program.getLanguageID() + "/" + program.getCompilerSpec().getCompilerSpecID() + "): " + @@ -2090,8 +2095,8 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E nameAndAddr = StringUtilities.pad(nameAndAddr, ' ', -paddedLen); testFileDigest.append(nameAndAddr); testFileDigest.append(" (GroupInfo @ "); - testFileDigest.append( - testGroup.controlBlock.getInfoStructureAddress().toString(true)); + testFileDigest + .append(testGroup.controlBlock.getInfoStructureAddress().toString(true)); testFileDigest.append(")"); if (duplicateTests.contains(testGroup.testGroupName)) { testFileDigest.append(" *DUPLICATE*"); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/.gitignore b/Ghidra/Features/Decompiler/src/decompile/cpp/.gitignore index 9b4cc5de8b..0cc09752d4 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/.gitignore +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/.gitignore @@ -7,9 +7,11 @@ decomp_dbg decomp_opt ghidra_dbg ghidra_opt +ghidra_test_dbg sleigh_dbg com_dbg com_opt +test_dbg ghi_dbg ghi_opt sla_dbg diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile b/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile index 76eed1458a..a19dfe4a99 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile @@ -91,11 +91,11 @@ GHIDRA= ghidra_arch inject_ghidra ghidra_translate loadimage_ghidra \ # Additional files specific to the sleigh compiler SLACOMP=slgh_compile slghparse slghscan # Additional special files that should not be considered part of the library -SPECIAL=consolemain sleighexample +SPECIAL=consolemain sleighexample test # Any additional modules for the command line decompiler EXTRA= $(filter-out $(CORE) $(DECCORE) $(SLEIGH) $(GHIDRA) $(SLACOMP) $(SPECIAL),$(ALL_NAMES)) -EXECS=decomp_dbg decomp_opt ghidra_dbg ghidra_opt sleigh_dbg sleigh_opt libdecomp_dbg.a libdecomp.a +EXECS=decomp_dbg decomp_opt ghidra_test_dbg ghidra_dbg ghidra_opt sleigh_dbg sleigh_opt libdecomp_dbg.a libdecomp.a # Possible conditional compilation flags # __TERMINAL__ # Turn on terminal support for console mode @@ -114,6 +114,9 @@ COMMANDLINE_NAMES=$(CORE) $(DECCORE) $(EXTRA) $(SLEIGH) consolemain COMMANDLINE_DEBUG=-DCPUI_DEBUG -D__TERMINAL__ COMMANDLINE_OPT=-D__TERMINAL__ +TEST_NAMES=$(CORE) $(DECCORE) $(SLEIGH) test +TEST_DEBUG=-D__TERMINAL__ -g -O0 + GHIDRA_NAMES=$(CORE) $(DECCORE) $(GHIDRA) GHIDRA_NAMES_DBG=$(GHIDRA_NAMES) callgraph ifacedecomp ifaceterm interface GHIDRA_DEBUG=-DCPUI_DEBUG @@ -133,6 +136,7 @@ LIBDECOMP_NAMES=$(CORE) $(DECCORE) $(EXTRA) $(SLEIGH) # object file macros COMMANDLINE_DBG_OBJS=$(COMMANDLINE_NAMES:%=com_dbg/%.o) COMMANDLINE_OPT_OBJS=$(COMMANDLINE_NAMES:%=com_opt/%.o) +TEST_DEBUG_OBJS=$(TEST_NAMES:%=test_dbg/%.o) GHIDRA_DBG_OBJS=$(GHIDRA_NAMES_DBG:%=ghi_dbg/%.o) GHIDRA_OPT_OBJS=$(GHIDRA_NAMES:%=ghi_opt/%.o) SLEIGH_DBG_OBJS=$(SLEIGH_NAMES:%=sla_dbg/%.o) @@ -183,6 +187,9 @@ endif ifeq ($(MAKECMDGOALS),decomp_opt) DEPNAMES=com_opt/depend endif +ifneq (,$(filter $(MAKECMDGOALS),ghidra_test_dbg test)) + DEPNAMES=test_dbg/depend +endif ifeq ($(MAKECMDGOALS),reallyclean) DEPNAMES= endif @@ -206,6 +213,8 @@ com_dbg/%.o: %.cc $(CXX) $(ARCH_TYPE) -c $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(COMMANDLINE_DEBUG) $< -o $@ com_opt/%.o: %.cc $(CXX) $(ARCH_TYPE) -c $(OPT_CXXFLAGS) $(ADDITIONAL_FLAGS) $(COMMANDLINE_OPT) $< -o $@ +test_dbg/%.o: %.cc + $(CXX) $(ARCH_TYPE) -c $(OPT_CXXFLAGS) $(ADDITIONAL_FLAGS) $(TEST_DEBUG) $< -o $@ ghi_dbg/%.o: %.cc $(CXX) $(ARCH_TYPE) -c $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(GHIDRA_DEBUG) $< -o $@ ghi_opt/%.o: %.cc @@ -238,6 +247,12 @@ decomp_dbg: $(COMMANDLINE_DBG_OBJS) decomp_opt: $(COMMANDLINE_OPT_OBJS) $(CXX) $(OPT_CXXFLAGS) $(ARCH_TYPE) -o decomp_opt $(COMMANDLINE_OPT_OBJS) $(BFDLIB) $(LNK) +ghidra_test_dbg: $(TEST_DEBUG_OBJS) + $(CXX) $(OPT_CXXFLAGS) $(ARCH_TYPE) -o ghidra_test_dbg $(TEST_DEBUG_OBJS) $(BFDLIB) $(LNK) + +test: ghidra_test_dbg + ./ghidra_test_dbg + ghidra_dbg: $(GHIDRA_DBG_OBJS) $(CXX) $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(MAKE_STATIC) $(ARCH_TYPE) -o ghidra_dbg $(GHIDRA_DBG_OBJS) $(LNK) @@ -324,6 +339,13 @@ com_opt/depend: $(COMMANDLINE_NAMES:%=%.cc) sed 's,\(.*\)\.o[ :]*,com_opt/\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ +test_dbg/depend: $(TEST_NAMES:%=%.cc) + mkdir -p test_dbg + @set -e; rm -f $@; \ + $(CXX) -MM $(TEST_DEBUG) $^ > $@.$$$$; \ + sed 's,\(.*\)\.o[ :]*,test_dbg/\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + ghi_dbg/depend: $(GHIDRA_NAMES_DBG:%=%.cc) mkdir -p ghi_dbg @set -e; rm -f $@; \ @@ -372,7 +394,7 @@ doc: doxygen Doxyfile clean: - rm -f com_dbg/*.o com_opt/*.o ghi_dbg/*.o ghi_opt/*.o sla_dbg/*.o sla_opt/*.o + rm -f com_dbg/*.o com_opt/*.o test_dbg/*.o ghi_dbg/*.o ghi_opt/*.o sla_dbg/*.o sla_opt/*.o rm -f *.gcov com_dbg/*.gcno com_dbg/*.gcda resetgcov: @@ -380,6 +402,6 @@ resetgcov: reallyclean: clean rm -rf coreext_*.cc coreext_*.hh ghidraext_*.cc ghidraext_*.hh consoleext_*.cc consoleext_*.hh - rm -rf com_dbg com_opt ghi_dbg ghi_opt sla_dbg sla_opt + rm -rf com_dbg com_opt test_dbg ghi_dbg ghi_opt sla_dbg sla_opt rm -f $(EXECS) TAGS *~ diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc index fe37245d79..5776decd1e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc @@ -249,7 +249,6 @@ double FloatFormat::getHostFloat(uintb encoding,floatclass *type) const if (exp == 0) { if ( frac == 0 ) { // Floating point zero *type = zero; - // FIXME: add on sign-bit for +0 or -0 allowed by standard return sgn ? -0.0 : +0.0; } *type = denormalized; @@ -259,7 +258,6 @@ double FloatFormat::getHostFloat(uintb encoding,floatclass *type) const else if (exp == maxexponent) { if ( frac == 0 ) { // Floating point infinity *type = infinity; - // FIXME: add on sign-bit for +inf or -inf allowed by standard return sgn ? -INFINITY : +INFINITY; } *type = nan; @@ -280,6 +278,27 @@ double FloatFormat::getHostFloat(uintb encoding,floatclass *type) const return createFloat(sgn,frac,exp); } +/// \brief Round a floating point value to the nearest even +/// +/// \param signif the significant bits of a floating point value +/// \param lowbitpos the position in signif of the floating point +/// \return true if we rounded up + +bool FloatFormat::roundToNearestEven(uintb &signif, int4 lowbitpos) + +{ + uintb lowbitmask = (lowbitpos < 8 * sizeof(uintb)) ? (1UL << lowbitpos) : 0; + uintb midbitmask = 1UL << (lowbitpos - 1); + uintb epsmask = midbitmask - 1; + bool odd = (signif & lowbitmask) != 0; + if ((signif & midbitmask) != 0 && ((signif & epsmask) != 0 || odd)) { + signif += midbitmask; + return true; + } + return false; +} + + /// \param host is the double value to convert /// \return the equivalent encoded value uintb FloatFormat::getEncoding(double host) const @@ -290,7 +309,7 @@ uintb FloatFormat::getEncoding(double host) const uintb signif; int4 exp; - type = extractExpSig(host,&sgn,&signif,&exp); + type = extractExpSig(host, &sgn, &signif, &exp); if (type == zero) return getZeroEncoding(sgn); else if (type == infinity) @@ -300,53 +319,114 @@ uintb FloatFormat::getEncoding(double host) const // convert exponent and fractional to their encodings exp += bias; - if (exp < 0) // Exponent is too small to represent - return getZeroEncoding(sgn); - if (exp > maxexponent) // Exponent is too big to represent + + if (exp < -frac_size) // Exponent is too small to represent + return getZeroEncoding(sgn); // TODO handle round to non-zero + + if (exp < 1) { // Must be denormalized + if (roundToNearestEven(signif, 8 * sizeof(uintb) - frac_size - exp)) { + // TODO handle round to normal case + if ((signif >> (8 * sizeof(uintb) - 1)) == 0) { + signif = 1UL << (8 * sizeof(uintb) - 1); + exp += 1; + } + } + uintb res = getZeroEncoding(sgn); + return setFractionalCode(res, signif >> (-exp)); + } + + if (roundToNearestEven(signif, 8 * sizeof(uintb) - frac_size - 1)) { + // if high bit is clear, then the add overflowed. Increase exp and set + // signif to 1. + if ((signif >> (8 * sizeof(uintb) - 1)) == 0) { + signif = 1UL << (8 * sizeof(uintb) - 1); + exp += 1; + } + } + + if (exp >= maxexponent) // Exponent is too big to represent return getInfinityEncoding(sgn); - if (jbitimplied && (exp !=0)) + + if (jbitimplied && (exp != 0)) signif <<= 1; // Cut off top bit (which should be 1) uintb res = 0; - res = setFractionalCode(res,signif); - res = setExponentCode(res,(uintb)exp); - return setSign(res,sgn); + res = setFractionalCode(res, signif); + res = setExponentCode(res, (uintb)exp); + return setSign(res, sgn); } + /// \param encoding is the value in the \e other FloatFormat /// \param formin is the \e other FloatFormat /// \return the equivalent value in \b this FloatFormat -uintb FloatFormat::convertEncoding(uintb encoding,const FloatFormat *formin) const +uintb FloatFormat::convertEncoding(uintb encoding, + const FloatFormat *formin) const { bool sgn = formin->extractSign(encoding); - uintb frac = formin->extractFractionalCode(encoding); + uintb signif = formin->extractFractionalCode(encoding); int4 exp = formin->extractExponentCode(encoding); - + if (exp == formin->maxexponent) { // NaN or INFINITY encoding exp = maxexponent; - } - else { - exp -= formin->bias; - exp += bias; - if (exp < 0) - return getZeroEncoding(sgn); - if (exp > maxexponent) + if (signif != 0) + return getNaNEncoding(sgn); + else return getInfinityEncoding(sgn); } - if (jbitimplied && !formin->jbitimplied) - frac <<= 1; // Cut off top bit (which should be 1) - else if (formin->jbitimplied && !jbitimplied) { - frac >>= 1; // Make room for 1 jbit - uintb highbit = 1; - highbit <<= 8*sizeof(uintb)-1; - frac |= highbit; // Stick bit in at top + + if (exp == 0) { // incoming is subnormal + if (signif == 0) + return getZeroEncoding(sgn); + + // normalize + int4 lz = count_leading_zeros(signif); + signif <<= lz; + exp = -formin->bias - lz; + } + else { // incoming is normal + exp -= formin->bias; + if (jbitimplied) + signif = (1UL << (8 * sizeof(uintb) - 1)) | (signif >> 1); } + exp += bias; + + if (exp < -frac_size) // Exponent is too small to represent + return getZeroEncoding(sgn); // TODO handle round to non-zero + + if (exp < 1) { // Must be denormalized + if (roundToNearestEven(signif, 8 * sizeof(uintb) - frac_size - exp)) { + // TODO handle carry to normal case + if ((signif >> (8 * sizeof(uintb) - 1)) == 0) { + signif = 1UL << (8 * sizeof(uintb) - 1); + exp += 1; + } + } + uintb res = getZeroEncoding(sgn); + return setFractionalCode(res, signif >> (-exp)); + } + + if (roundToNearestEven(signif, 8 * sizeof(uintb) - frac_size - 1)) { + // if high bit is clear, then the add overflowed. Increase exp and set + // signif to 1. + if ((signif >> (8 * sizeof(uintb) - 1)) == 0) { + signif = 1UL << (8 * sizeof(uintb) - 1); + exp += 1; + } + } + + if (exp >= maxexponent) // Exponent is too big to represent + return getInfinityEncoding(sgn); + + if (jbitimplied && (exp != 0)) + signif <<= 1; // Cut off top bit (which should be 1) + uintb res = 0; - res = setFractionalCode(res,frac); - res = setExponentCode(res,(uintb)exp); - return setSign(res,sgn); + res = setFractionalCode(res, signif); + res = setExponentCode(res, (uintb)exp); + return setSign(res, sgn); } // Currently we emulate floating point operations on the target @@ -513,9 +593,7 @@ uintb FloatFormat::opInt2Float(uintb a,int4 sizein) const uintb FloatFormat::opFloat2Float(uintb a,const FloatFormat &outformat) const { - floatclass type; - double val = getHostFloat(a,&type); - return outformat.getEncoding(val); + return outformat.convertEncoding(a, this); } /// \param a is an encoded floating-point value @@ -559,7 +637,8 @@ uintb FloatFormat::opRound(uintb a) const { floatclass type; double val = getHostFloat(a,&type); - return getEncoding(floor(val+0.5)); + // return getEncoding(floor(val+.5)); // round half up + return getEncoding(round(val)); // round half away from zero } /// Write the format out to a \ XML tag. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/float.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/float.hh index 8e66916e7b..fff9075f19 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/float.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/float.hh @@ -50,6 +50,7 @@ private: bool jbitimplied; ///< Set to \b true if integer bit of 1 is assumed static double createFloat(bool sign,uintb signif,int4 exp); ///< Create a double given sign, fractional, and exponent static floatclass extractExpSig(double x,bool *sgn,uintb *signif,int4 *exp); + static bool roundToNearestEven(uintb &signif, int4 lowbitpos); uintb setFractionalCode(uintb x,uintb code) const; ///< Set the fractional part of an encoded value uintb setSign(uintb x,bool sign) const; ///< Set the sign bit of an encoded value uintb setExponentCode(uintb x,uintb code) const; ///< Set the exponent of an encoded value diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/test.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/test.cc new file mode 100644 index 0000000000..ab99382a3c --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/test.cc @@ -0,0 +1,482 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/// \file test.cc +/// \brief Unit tests for Ghidra C++ components. + +#include "float.hh" +#include "opbehavior.hh" +#include "test.hh" + +#include +#include +#include + +#include +#include + +// utility functions +float floatFromRawBits(uintb e) { + float f; + memcpy(&f, &e, 4); + return f; +} + +uintb floatToRawBits(float f) { + uintb result = 0; + memcpy(&result, &f, 4); + return result; +} + +double doubleFromRawBits(uintb e) { + double f; + memcpy(&f, &e, 8); + return f; +} + +uintb doubleToRawBits(double f) { + uintb result = 0; + memcpy(&result, &f, 8); + return result; +} + +// macros to preserve call site +#define ASSERT_FLOAT_ENCODING(f) \ + do { \ + FloatFormat format(4); \ + \ + uintb true_encoding = floatToRawBits(f); \ + uintb encoding = format.getEncoding(f); \ + \ + ASSERT_EQUALS(true_encoding, encoding); \ + } while (0); + +#define ASSERT_DOUBLE_ENCODING(f) \ + do { \ + FloatFormat format(8); \ + \ + uintb true_encoding = doubleToRawBits(f); \ + uintb encoding = format.getEncoding(f); \ + \ + ASSERT_EQUALS(true_encoding, encoding); \ + } while (0); + +//// FloatFormat tests + +static std::vector float_test_values{ + -0.0f, + +0.0f, + -1.0f, + +1.0f, + + -1.234f, + +1.234f, + + -std::numeric_limits::denorm_min(), + std::numeric_limits::denorm_min(), + + std::numeric_limits::min() - std::numeric_limits::denorm_min(), + std::numeric_limits::min(), + std::numeric_limits::min() + std::numeric_limits::denorm_min(), + + -std::numeric_limits::min() + std::numeric_limits::denorm_min(), + -std::numeric_limits::min(), + -std::numeric_limits::min() - std::numeric_limits::denorm_min(), + + std::numeric_limits::max(), + + std::numeric_limits::quiet_NaN(), + + -std::numeric_limits::infinity(), + std::numeric_limits::infinity() +}; + +static std::vector int_test_values = { + 0, -1, 1, 1234, -1234, std::numeric_limits::min(), std::numeric_limits::max() +}; + +TEST(float_encoding_normal) { + ASSERT_FLOAT_ENCODING(1.234); + ASSERT_FLOAT_ENCODING(-1.234); +} + +TEST(double_encoding_normal) { + ASSERT_DOUBLE_ENCODING(1.234); + ASSERT_DOUBLE_ENCODING(-1.234); +} + +TEST(float_encoding_nan) { + ASSERT_FLOAT_ENCODING(std::numeric_limits::quiet_NaN()); + ASSERT_FLOAT_ENCODING(-std::numeric_limits::quiet_NaN()); +} + +TEST(double_encoding_nan) { + ASSERT_DOUBLE_ENCODING(std::numeric_limits::quiet_NaN()); + ASSERT_DOUBLE_ENCODING(-std::numeric_limits::quiet_NaN()); +} + +TEST(float_encoding_subnormal) { + ASSERT_FLOAT_ENCODING(std::numeric_limits::denorm_min()); + ASSERT_FLOAT_ENCODING(-std::numeric_limits::denorm_min()); +} + +TEST(double_encoding_subnormal) { + ASSERT_DOUBLE_ENCODING(std::numeric_limits::denorm_min()); + ASSERT_DOUBLE_ENCODING(-std::numeric_limits::denorm_min()); +} + +TEST(float_encoding_min_normal) { + ASSERT_FLOAT_ENCODING(std::numeric_limits::min()); + ASSERT_FLOAT_ENCODING(-std::numeric_limits::min()); +} + +TEST(double_encoding_min_normal) { + ASSERT_DOUBLE_ENCODING(std::numeric_limits::min()); + ASSERT_DOUBLE_ENCODING(-std::numeric_limits::min()); +} + +TEST(float_encoding_infinity) { + ASSERT_FLOAT_ENCODING(std::numeric_limits::infinity()); + ASSERT_FLOAT_ENCODING(-std::numeric_limits::infinity()); +} + +TEST(double_encoding_infinity) { + ASSERT_DOUBLE_ENCODING(std::numeric_limits::infinity()); + ASSERT_DOUBLE_ENCODING(-std::numeric_limits::infinity()); +} + +TEST(float_midpoint_rounding) { + FloatFormat ff(4); + // IEEE754 recommends "round to nearest even" for binary formats, like single and double + // precision floating point. It rounds to the nearest integer (significand) when unambiguous, + // and to the nearest even on the midpoint. + + // There are 52 bits of significand in a double and 23 in a float. + // Below we construct a sequence of double precision values to demonstrate each case + // in rounding, + + // d0 - zeros in low 29 bits, round down + // d1 - on the rounding midpoint with integer even integer part, round down + // d2 - just above the midpoint, round up + double d0 = doubleFromRawBits(0x4010000000000000L); + double d1 = doubleFromRawBits(0x4010000010000000L); + double d2 = doubleFromRawBits(0x4010000010000001L); + + // d3 - zeros in low 29 bits, round down + // d4 - on the rounding midpoint with integer part odd, round up + // d5 - just above the midpoint, round up + double d3 = doubleFromRawBits(0x4010000020000000L); + double d4 = doubleFromRawBits(0x4010000030000000L); + double d5 = doubleFromRawBits(0x4010000030000001L); + + float f0 = (float)d0; + float f1 = (float)d1; + float f2 = (float)d2; + float f3 = (float)d3; + float f4 = (float)d4; + float f5 = (float)d5; + + uintb e0 = ff.getEncoding(d0); + uintb e1 = ff.getEncoding(d1); + uintb e2 = ff.getEncoding(d2); + uintb e3 = ff.getEncoding(d3); + uintb e4 = ff.getEncoding(d4); + uintb e5 = ff.getEncoding(d5); + + ASSERT_EQUALS(floatToRawBits(f0), e0); + ASSERT_EQUALS(floatToRawBits(f1), e1); + ASSERT_EQUALS(floatToRawBits(f2), e2); + ASSERT_EQUALS(floatToRawBits(f3), e3); + ASSERT_EQUALS(floatToRawBits(f4), e4); + ASSERT_EQUALS(floatToRawBits(f5), e5); + + ASSERT_EQUALS(e0, e1); + ASSERT_NOT_EQUALS(e1, e2); + + ASSERT_NOT_EQUALS(e3, e4); + ASSERT_EQUALS(e4, e5); +} + +// op tests + +// generated + +TEST(float_opNan) { + FloatFormat format(4); + + for(float f:float_test_values) { + uintb true_result = isnan(f); + uintb encoding = format.getEncoding(f); + uintb result = format.opNan(encoding); + + ASSERT_EQUALS(true_result, result); + } +} + + +TEST(float_opNeg) { + FloatFormat format(4); + + for(float f:float_test_values) { + uintb true_result = floatToRawBits(-f); + uintb encoding = format.getEncoding(f); + uintb result = format.opNeg(encoding); + + ASSERT_EQUALS(true_result, result); + } +} + + +TEST(float_opAbs) { + FloatFormat format(4); + + for(float f:float_test_values) { + uintb true_result = floatToRawBits(abs(f)); + uintb encoding = format.getEncoding(f); + uintb result = format.opAbs(encoding); + + ASSERT_EQUALS(true_result, result); + } +} + + +TEST(float_opSqrt) { + FloatFormat format(4); + + for(float f:float_test_values) { + uintb true_result = floatToRawBits(sqrtf(f)); + uintb encoding = format.getEncoding(f); + uintb result = format.opSqrt(encoding); + + ASSERT_EQUALS(true_result, result); + } +} + + +TEST(float_opCeil) { + FloatFormat format(4); + + for(float f:float_test_values) { + uintb true_result = floatToRawBits(ceilf(f)); + uintb encoding = format.getEncoding(f); + uintb result = format.opCeil(encoding); + + ASSERT_EQUALS(true_result, result); + } +} + + +TEST(float_opFloor) { + FloatFormat format(4); + + for(float f:float_test_values) { + uintb true_result = floatToRawBits(floorf(f)); + uintb encoding = format.getEncoding(f); + uintb result = format.opFloor(encoding); + + ASSERT_EQUALS(true_result, result); + } +} + + +TEST(float_opRound) { + FloatFormat format(4); + + for(float f:float_test_values) { + uintb true_result = floatToRawBits(roundf(f)); + uintb encoding = format.getEncoding(f); + uintb result = format.opRound(encoding); + + ASSERT_EQUALS(true_result, result); + } +} + + +TEST(float_opInt2Float_size4) { + FloatFormat format(4); + + for(int i:int_test_values) { + uintb true_result = floatToRawBits((float)i); + uintb result = format.opInt2Float(i, 4); + + ASSERT_EQUALS(true_result, result); + } +} +// TODO other sized ints + +TEST(float_to_double_opFloat2Float) { + FloatFormat format(4); + FloatFormat format8(8); + + for(float f:float_test_values) { + uintb true_result = doubleToRawBits((double)f); + uintb encoding = format.getEncoding(f); + uintb result = format.opFloat2Float(encoding, format8); + + ASSERT_EQUALS(true_result, result); + } +} + +// TODO float2float going the other direction, double_to_float_opFloat2Float + + +TEST(float_opTrunc_to_int) { + FloatFormat format(4); + FloatFormat format8(8); + + for(float f:float_test_values) { + // avoid undefined behavior + if((int64_t)f > std::numeric_limits::max() || (int64_t)f < std::numeric_limits::min()) + continue; + uintb true_result = ((uintb)(int32_t)f) & 0xffffffff; + uintb encoding = format.getEncoding(f); + uintb result = format.opTrunc(encoding, 4); + + ASSERT_EQUALS(true_result, result); + } +} + +// TODO trunc to other sizes + + + +TEST(float_opEqual) { + FloatFormat format(4); + + for(float f1:float_test_values) { + uintb encoding1 = format.getEncoding(f1); + for(float f2:float_test_values) { + uintb true_result = (f1==f2); + uintb encoding2 = format.getEncoding(f2); + uintb result = format.opEqual(encoding1, encoding2); + + ASSERT_EQUALS(true_result, result); + } + } +} + + +TEST(float_opNotEqual) { + FloatFormat format(4); + + for(float f1:float_test_values) { + uintb encoding1 = format.getEncoding(f1); + for(float f2:float_test_values) { + uintb true_result = (f1!=f2); + uintb encoding2 = format.getEncoding(f2); + uintb result = format.opNotEqual(encoding1, encoding2); + + ASSERT_EQUALS(true_result, result); + } + } +} + + +TEST(float_opLess) { + FloatFormat format(4); + + for(float f1:float_test_values) { + uintb encoding1 = format.getEncoding(f1); + for(float f2:float_test_values) { + uintb true_result = (f1 +#include +#include +#include +#include +#include + +namespace { + struct Test; + typedef void (*testfunc_t)(); + + std::vector tests; + + struct Test { + std::string name; + testfunc_t func; + + Test(const std::string &name, testfunc_t func) : name(name), func(func) { + tests.push_back(this); + } + }; +} // namespace + +#define TEST(testname) \ + void testname(); \ + Test testname##_obj{ #testname, testname }; \ + void testname() + +#define ASSERT(test) \ + if (!(test)) { \ + std::cerr << " failed at " << __FILE__ << ":" << __LINE__ << " asserting \"" << #test << "\"." << std::endl; \ + throw 0; \ + } + +#define ASSERT_EQUALS(a, b) \ + if ((a) != (b)) { \ + std::stringstream ssa, ssb; \ + ssa << (a); \ + ssb << (b); \ + std::cerr << " failed at " << __FILE__ << ":" << __LINE__ << " asserting \"" << ssa.str() \ + << " == " << ssb.str() << "\"." << std::endl; \ + throw 0; \ + } + +#define ASSERT_NOT_EQUALS(a, b) \ + if ((a) == (b)) { \ + std::stringstream ssa, ssb; \ + ssa << (a); \ + ssb << (b); \ + std::cerr << " failed at " << __FILE__ << ":" << __LINE__ << " asserting \"" << ssa.str() \ + << " != " << ssb.str() << "\"." << std::endl; \ + throw 0; \ + } + +int main(int argc, char **argv) { + int total = 0; + int passed = 0; + + std::set testnames(argv + 1, argv + argc); + + for (auto &t : tests) { + if(testnames.size()>0 && testnames.find(t->name)==testnames.end()) { + continue; + } + std::cerr << "testing : " << t->name << " ..." << std::endl; + ++total; + try { + t->func(); + ++passed; + std::cerr << " passed." << std::endl; + } catch (...) { + } + } + std::cerr << "==============================" << std::endl; + std::cerr << passed << "/" << total << " tests passed." << std::endl; +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/BigFloat.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/BigFloat.java new file mode 100644 index 0000000000..f80938011f --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/BigFloat.java @@ -0,0 +1,993 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.pcode.floatformat; + +import java.math.*; + +/** + * An IEEE 754 floating point class. + * + *

Values represented: + *

    + *
  • QUIET_NAN, SIGNALED_NAN
  • + *
  • -INF, +INF
  • + *
  • value = sign * unscaled * 2 ^ (scale-fracbits)
  • + *
+ * sign = -1 or +1, unscaled has at most fracbits+1 bits, and scale is at most expbits bits. + * + *

Operations compute exact result then round to nearest even. + */ +public strictfp class BigFloat implements Comparable { + final int fracbits; // there are fracbits+1 significant bits. + final int expbits; // # bits used for exponent + + final int maxScale; + final int minScale; + + FloatKind kind; + + // -1, +1 + int sign; + // normal numbers have unscaled.bitLength() = fracbits+1 + // subnormal numbers have scale=0 and unscaled.bitLength() <= fracbits + BigInteger unscaled; + int scale; + + /** + * Construct a BigFloat. If kind is FINITE, the value is sign*unscaled*2^(scale-fracbits) + * + * @param fracbits number of fractional bits + * @param expbits maximum number of bits in exponent + * @param kind the Kind, FINITE, INFINITE, ... + * @param sign +1 or -1 + * @param unscaled the value's mantissa + * @param scale value's scale + */ + public BigFloat(int fracbits, int expbits, FloatKind kind, int sign, BigInteger unscaled, + int scale) { + this.fracbits = fracbits; + this.expbits = expbits; + this.kind = kind; + this.sign = sign; + this.unscaled = unscaled; + this.scale = scale; + + this.maxScale = (1 << (expbits - 1)) - 1; + this.minScale = 1 - this.maxScale; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + expbits; + result = prime * result + fracbits; + result = prime * result + kind.hashCode(); + switch (kind) { + case FINITE: + result = prime * result + sign; + result = prime * result + scale; + result = prime * result + unscaled.hashCode(); + break; + case INFINITE: + result = prime * result + sign; + break; + case QUIET_NAN: + case SIGNALING_NAN: + break; + } + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + BigFloat other = (BigFloat) obj; + if (expbits != other.expbits) { + return false; + } + if (fracbits != other.fracbits) { + return false; + } + if (kind != other.kind) { + return false; + } + switch (kind) { + case FINITE: + if (sign != other.sign) { + return false; + } + if (scale != other.scale) { + return false; + } + if (!unscaled.equals(other.unscaled)) { + return false; + + } + break; + case INFINITE: + if (sign != other.sign) { + return false; + } + break; + case QUIET_NAN: + case SIGNALING_NAN: + break; + } + return true; + } + + /** + * Return the BigFloat with the given number of bits representing the given BigInteger. + * + * @param fracbits number of fractional bits + * @param expbits number of bits in the exponent + * @param i an integer + * @return a BigFloat representing i + */ + public static BigFloat valueOf(int fracbits, int expbits, BigInteger i) { + BigFloat f = new BigFloat(fracbits, expbits, FloatKind.FINITE, i.signum() >= 0 ? +1 : -1, + i.abs(), fracbits); + f.scaleUpTo(fracbits + 1); + return f; + } + + /** + * Return the BigFloat with the given number of bits representing zero. + * + * @param fracbits number of fractional bits + * @param expbits number of bits in the exponent + * @param sign +1 or -1 + * @return a BigFloat representing +zero or -zero + */ + public static BigFloat zero(int fracbits, int expbits, int sign) { + return new BigFloat(fracbits, expbits, FloatKind.FINITE, sign, BigInteger.ZERO, + 2 - (1 << (expbits - 1))); + } + + /** + * Return the BigFloat with the given number of bits representing (positive) zero. + * + * @param fracbits number of fractional bits + * @param expbits number of bits in the exponent + * @return a BigFloat representing +zero + */ + public static BigFloat zero(int fracbits, int expbits) { + return zero(fracbits, expbits, +1); + } + + /** + * @param fracbits number of fractional bits + * @param expbits number of bits in the exponent + * @param sign +1 or -1 + * @return +inf or -inf + */ + public static BigFloat infinity(int fracbits, int expbits, int sign) { + return new BigFloat(fracbits, expbits, FloatKind.INFINITE, sign, + BigInteger.ONE.shiftLeft(fracbits), (1 << (expbits - 1)) - 1); + } + + /** + * Return the BigFloat with the given number of bits representing (quiet) NaN. + * + * @param fracbits number of fractional bits + * @param expbits number of bits in the exponent + * @param sign +1 or -1 + * @return a BigFloat representing (quiet) NaN + */ + public static BigFloat quietNaN(int fracbits, int expbits, int sign) { + return new BigFloat(fracbits, expbits, FloatKind.QUIET_NAN, sign, BigInteger.ZERO, + (1 << (expbits - 1)) - 1); + } + + private void upscale(int nbits) { + unscaled = unscaled.shiftLeft(nbits); + scale -= nbits; + } + + // guarantee at least significant bits (fractbits+1) plus one for rounding + protected void scaleUpTo(int newLength) { + if (kind != FloatKind.FINITE) { + throw new AssertionError("scaling of non-finite float!"); + } + int d = newLength - this.unscaled.bitLength(); + if (d > 0) { + this.upscale(d); + } + } + + /** + * @return {@code true} if this BigFloat is FINITE and normal + */ + public boolean isNormal() { + return kind == FloatKind.FINITE && unscaled.bitLength() >= fracbits + 1; + } + + /** + * This function is used internally to round after a computation. + * + *

Assume that the true value is + * sign * (unscaled + eps) * 2 ^ (scale-fracbits) + * and + * unscaled.bitLength() > fracbits+1 + * (or the value is subnormal with at least 1 bit of extra precision) + * + * @param eps < 1 + */ + protected void internalRound(boolean eps) { + if (kind != FloatKind.FINITE) { + throw new AssertionError("Rounding non-finite float"); + } + if (unscaled.signum() == 0) { + if (eps) { + throw new AssertionError("Rounding zero + epsilon, need bit length"); + } + makeZero(); + return; + } + + int extrabits = Math.max(unscaled.bitLength() - (fracbits + 1), minScale - scale); + + if (extrabits <= 0) { + throw new AssertionError("Rounding with no extra bits of precision"); + } + + int midbit = extrabits - 1; + boolean midbitset = this.unscaled.testBit(midbit); + eps |= unscaled.getLowestSetBit() < midbit; + unscaled = unscaled.shiftRight(extrabits); + scale += extrabits; + boolean odd = unscaled.testBit(0); + + if (midbitset && (eps || odd)) { + unscaled = unscaled.add(BigInteger.ONE); + // handle overflowing carry + if (unscaled.bitLength() > fracbits + 1) { + assert (unscaled.bitLength() == unscaled.getLowestSetBit() + 1); + unscaled = unscaled.shiftRight(1); + scale += 1; + } + } + + if (scale > maxScale) { + kind = FloatKind.INFINITE; + } + } + + protected int getLeadBitPos() { + if (kind != FloatKind.FINITE || unscaled.signum() == 0) { + throw new AssertionError("lead bit of non-finite or zero"); + } + return unscaled.bitLength() - fracbits + scale; + } + + /** + * If finite, the returned BigDecimal is exactly equal to this. If not finite, one of the + * FloatFormat.BIG_* constants is returned. + * + * @return a BigDecimal + */ + public BigDecimal toBigDecimal() { + switch (kind) { + case FINITE: + // sign * unscaled * 2^(scale-fracbits) + int iscale = scale - fracbits; + BigDecimal x; + if (iscale >= 0) { + x = new BigDecimal(unscaled.shiftLeft(iscale)); + } + else { + x = new BigDecimal(unscaled.multiply(BigInteger.valueOf(5).pow(-iscale)), + -iscale); + } + if (sign < 0) { + x = x.negate(); + } + return x; + case INFINITE: + return sign < 0 ? FloatFormat.BIG_NEGATIVE_INFINITY + : FloatFormat.BIG_POSITIVE_INFINITY; + case QUIET_NAN: + case SIGNALING_NAN: + return FloatFormat.BIG_NaN; + default: + throw new AssertionError("unknown BigFloat kind: " + kind); + } + } + + public String toBinaryString() { + switch (kind) { + case QUIET_NAN: + return "qNaN"; + case SIGNALING_NAN: + return "sNaN"; + case INFINITE: + if (sign < 0) + return "-inf"; + return "+inf"; + case FINITE: + String s = (sign < 0) ? "-" : ""; + + int ascale = scale; + + String binary; + if (this.isNormal()) { + binary = "1." + unscaled.toString(2).substring(1); + ascale += (unscaled.bitLength() - (fracbits + 1)); + } + else { // subnormal + assert (unscaled.bitLength() <= fracbits); + if (unscaled.equals(BigInteger.ZERO)) { + return String.format("%s0b0.0", s); + } + binary = + "0." + "0".repeat(fracbits - unscaled.bitLength()) + unscaled.toString(2); + } + binary = binary.replaceAll("0*$", ""); + if (binary.endsWith(".")) { + binary += "0"; + } + return String.format("%s0b%s * 2^%d", s, binary, ascale); + default: + throw new AssertionError("unexpected kind " + kind); + } + } + + protected void makeSignalingNaN() { + this.kind = FloatKind.SIGNALING_NAN; + } + + protected void makeQuietNaN() { + this.kind = FloatKind.QUIET_NAN; + } + + /** + * @return {@code true} if this BigFloat is NaN + */ + public boolean isNaN() { + return kind == FloatKind.QUIET_NAN || kind == FloatKind.SIGNALING_NAN; + } + + protected void makeZero() { + this.kind = FloatKind.FINITE; + this.unscaled = BigInteger.ZERO; + this.scale = minScale; + } + + /** + * @return {@code true} if this BigFloat is infinite + */ + public boolean isInfinite() { + return kind == FloatKind.INFINITE; + } + + /** + * @return {@code true} if this BigFloat is zero + */ + public boolean isZero() { + return this.kind == FloatKind.FINITE && unscaled.equals(BigInteger.ZERO); + } + + /** + * @return a copy of this BigFloat + */ + public BigFloat copy() { + return new BigFloat(fracbits, expbits, kind, sign, unscaled, scale); + } + + // assuming same fracbits and expbits... + protected void copyFrom(BigFloat other) { + this.kind = other.kind; + this.sign = other.sign; + this.unscaled = other.unscaled; + this.scale = other.scale; + } + + /** + * @param a a BigFloat + * @param b a BigFloat + * @return {@code a/b} + */ + public static BigFloat div(BigFloat a, BigFloat b) { + BigFloat c = a.copy(); + c.div(b); + return c; + } + + /** + * {@code this/=other} + * + * @param other a BigFloat + */ + public void div(BigFloat other) { + if (this.isNaN() || other.isNaN()) { + makeQuietNaN(); + return; + } + + if (this.isInfinite()) { + if (other.isInfinite()) { + makeQuietNaN(); + } + else { + sign *= other.sign; + } + return; + } + + // this is finite + switch (other.kind) { + case QUIET_NAN: + case SIGNALING_NAN: + this.makeQuietNaN(); + return; + case INFINITE: + makeZero(); + sign *= other.sign; + return; + case FINITE: + break; + default: + throw new AssertionError("unexpected kind " + other.kind); + } + + if (other.isZero()) { + if (this.isZero()) { + makeQuietNaN(); + } + else { + this.kind = FloatKind.INFINITE; + this.sign *= other.sign; + } + return; + } + // this is finite, other is finite non zero + + // update representations so that this.unscaled has at fracbits+2 -- normal precision plus one for rounding. + // + // for numbers a,b + // floor(a)-floor(b)-1 <= floor(a-b) <= floor(a)-floor(b) + // nbits(x) = floor(log_2(x))+1, so + // nbits(x) - nbits(y) <= nbits(x/y) <= nbits(x) - nbits(y) + 1 + // so + // this + lshift - other = fracbits+2 => + int lshift = fracbits + 2 + other.unscaled.bitLength() - this.unscaled.bitLength(); + this.upscale(lshift); + + BigInteger qr[] = this.unscaled.divideAndRemainder(other.unscaled); + BigInteger q = qr[0]; + BigInteger r = qr[1]; + + this.sign *= other.sign; + this.scale -= other.scale - fracbits; + this.unscaled = q; + this.internalRound(r.signum() != 0); + } + + /** + * @param a a BigFloat + * @param b a BigFloat + * @return {@code a*b} + */ + public static BigFloat mul(BigFloat a, BigFloat b) { + BigFloat c = a.copy(); + c.mul(b); + return c; + } + + /** + * {@code this*=other} + * + * @param other a BigFloat + */ + public void mul(BigFloat other) { + if (this.isNaN() || other.isNaN()) { + this.makeQuietNaN(); + return; + } + if ((this.isZero() && other.isInfinite()) || (this.isInfinite() && other.isZero())) { + this.makeQuietNaN(); + return; + } + + if (this.isInfinite() || other.isInfinite()) { + this.kind = FloatKind.INFINITE; + this.sign *= other.sign; + return; + } + + // this and other are finite + this.sign *= other.sign; + this.unscaled = this.unscaled.multiply(other.unscaled); + this.scale += other.scale - fracbits; + + this.scaleUpTo(fracbits + 2); + this.internalRound(false); + } + + /** + * @param a a BigFloat + * @param b a BigFloat + * @return {@code a+b} + */ + public static BigFloat add(BigFloat a, BigFloat b) { + BigFloat c = a.copy(); + c.add(b); + return c; + } + + /** + * {@code this+=other} + * + * @param other a BigFloat + */ + public void add(BigFloat other) { + if (this.isNaN() || other.isNaN()) { + this.makeQuietNaN(); + return; + } + if (this.isInfinite() && other.isInfinite()) { + if (this.sign != other.sign) { + this.makeQuietNaN(); + } + return; + } + if (this.isInfinite()) { + return; + } + if (other.isInfinite()) { + copyFrom(other); + return; + } + + if (other.isZero()) { + if (this.isZero()) { + this.sign = (this.sign < 0 && other.sign < 0) ? -1 : 1; + } + return; + } + if (this.isZero()) { + copyFrom(other); + return; + } + + if (this.sign == other.sign) { + add0(other); + } + else { + sub0(other); + } + } + + /** + * @param a a BigFloat + * @param b a BigFloat + * @return {@code a-b} + */ + public static BigFloat sub(BigFloat a, BigFloat b) { + BigFloat c = b.copy(); + c.sign *= -1; + c.add(a); + if (c.isZero()) { + c.sign = (a.sign < 0 && b.sign > 0) ? -1 : 1; + } + return c; + } + + /** + * {@code this-=other} + * + * @param other a BigFloat + */ + public void sub(BigFloat other) { + int thissign = this.sign; + BigFloat nother = other.copy(); + nother.sign *= -1; + this.add(nother); + if (this.isZero()) { + this.sign = (thissign < 0 && nother.sign < 0) ? -1 : 1; + } + } + + // assume this and other are finite with the same sign, neither is zero + protected void add0(BigFloat other) { + int d = this.scale - other.scale; + + if (d > fracbits + 1) { + return; + } + else if (d < -(fracbits + 1)) { + this.copyFrom(other); + return; + } + boolean residue; + BigFloat a; + BigFloat b; + + if (d >= 0) { + a = this; + b = other; + } + else { + d = -d; + a = other; + b = this; + } + + residue = b.unscaled.getLowestSetBit() < d - 1; + this.scale = a.scale - 1; + this.unscaled = a.unscaled.shiftLeft(1).add(b.unscaled.shiftRight(d - 1)); + + scaleUpTo(fracbits + 2); + internalRound(residue); + } + + // assume this and other are finite with the opposite sign, neither is zero + protected void sub0(BigFloat other) { + int d = this.scale - other.scale; + + if (d > fracbits + 2) { + return; + } + else if (d < -(fracbits + 2)) { + this.copyFrom(other); + return; + } + boolean residue; + BigFloat a; + BigFloat b; + if (d >= 0) { + a = this; + b = other; + } + else { + d = -d; + a = other; + b = this; + } + + // d <= 0 is ok.. no residue and right shift will become left shift + residue = b.unscaled.getLowestSetBit() < d - 2; + this.sign = a.sign; + this.scale = a.scale - 2; + BigInteger x = b.unscaled; + x = x.shiftRight(d - 2); + if (residue) { + x = x.add(BigInteger.ONE); + } + + this.unscaled = a.unscaled.shiftLeft(2).subtract(x); + if (this.unscaled.signum() == 0) { + this.sign = 1; // cancellation results in positive 0. + } + else if (this.unscaled.signum() < 0) { + this.sign *= -1; + this.unscaled = this.unscaled.negate(); + } + scaleUpTo(fracbits + 2); + internalRound(residue); + } + + /** + * @param a a BigFloat + * @return the square root of {@code a} + */ + public static BigFloat sqrt(BigFloat a) { + BigFloat c = a.copy(); + c.sqrt(); + return c; + } + + /** + * {@code this=sqrt(this)} + * + *

Square root by abacus algorithm, Martin Guy @ UKC, June 1985. + * From a book on programming abaci by Mr C. Woo. + * Argument is a positive integer, as is result. + * + *

adapted from http://medialab.freaknet.org/martin/src/sqrt/sqrt.c + */ + public void sqrt() { + if (this.isZero()) { + return; + } + + if (this.isNaN() || this.sign == -1) { + makeQuietNaN(); + return; + } + + if (this.isInfinite()) { + return; + } + BigInteger residue; + BigInteger result; + BigInteger bit; + + //// force at least fracbits+2 bits of precision in the result + int sigbits = 2 * fracbits + 3; + this.scaleUpTo(sigbits); + + // scale+fracbits needs to be even for the sqrt computation + if (((scale + fracbits) & 1) != 0) { + upscale(1); + } + + residue = unscaled; + result = BigInteger.ZERO; + + /* "bit" starts at the highest 4 power <= n. */ + int pow = residue.bitLength() - 1; // highest 2 power <= n + pow -= pow & 1; // highest 4 power + bit = BigInteger.ONE.shiftLeft(pow); + + while (bit.signum() != 0) { + BigInteger resp1 = result.add(bit); + if (residue.compareTo(resp1) >= 0) { + residue = residue.subtract(resp1); + result = result.add(bit.shiftLeft(1)); + } + result = result.shiftRight(1); + bit = bit.shiftRight(2); + } + + unscaled = result; + scale = (scale + fracbits) / 2; + + internalRound(residue.signum() != 0); + } + + // floor, ignoring sign + private void floor0() { + // value = unscaled * 2^(scale-fracbits) + if (scale < 0) { + makeZero(); + return; + } + int nbitsUnderOne = fracbits - scale; + unscaled = unscaled.shiftRight(nbitsUnderOne).shiftLeft(nbitsUnderOne); + } + + // sign is not set + private void makeOne() { + kind = FloatKind.FINITE; + scale = 0; + unscaled = BigInteger.ONE.shiftLeft(fracbits); + } + + // ceil, ignoring sign + private void ceil0() { + if (isZero()) { + return; + } + else if (scale < 0) { + makeOne(); + return; + } + + int nbitsUnderOne = fracbits - scale; + boolean increment = unscaled.getLowestSetBit() < nbitsUnderOne; + unscaled = unscaled.shiftRight(nbitsUnderOne).shiftLeft(nbitsUnderOne); + if (increment) { + unscaled = unscaled.add(BigInteger.ONE.shiftLeft(nbitsUnderOne)); + } + + // if we carry to a new bit, change the scale + if (unscaled.bitLength() > fracbits + 1) { + upscale(-1); + } + } + + /** + * @param a a BigFloat + * @return {@code floor(a)} + */ + public static BigFloat floor(BigFloat a) { + BigFloat b = a.copy(); + b.floor(); + return b; + } + + /** + * {@code this=floor(this)} + */ + public void floor() { + switch (kind) { + case INFINITE: + return; + case SIGNALING_NAN: + makeQuietNaN(); + case QUIET_NAN: + return; + case FINITE: + break; + } + + if (sign >= 0) { + floor0(); + } + else { + ceil0(); + } + } + + /** + * @param a a BigFloat + * @return {@code ceil(a)} + */ + public static BigFloat ceil(BigFloat a) { + BigFloat b = a.copy(); + b.ceil(); + return b; + } + + /** + * {@code this=ceil(this)} + */ + public void ceil() { + switch (kind) { + case INFINITE: + return; + case SIGNALING_NAN: + makeQuietNaN(); + case QUIET_NAN: + return; + case FINITE: + break; + } + + if (sign >= 0) { + ceil0(); + } + else { + floor0(); + } + } + + /** + * @param a a BigFloat + * @return {@code trunc(a)} (round toward zero) + */ + public static BigFloat trunc(BigFloat a) { + BigFloat b = a.copy(); + b.trunc(); + return b; + } + + /** + * {@code this=trunc(this)} (round toward zero) + */ + public void trunc() { + floor0(); + } + + /** + * {@code this*=-1} + */ + public void negate() { + this.sign *= -1; + } + + /** + * @param a a BigFloat + * @return {@code -a} + */ + public static BigFloat negate(BigFloat a) { + BigFloat b = a.copy(); + b.negate(); + return b; + } + + /** + * @param a a BigFloat + * @return {@code abs(a)} + */ + public static BigFloat abs(BigFloat a) { + BigFloat b = a.copy(); + b.abs(); + return b; + } + + /** + * {@code this=abs(this)} + */ + public void abs() { + this.sign = 1; + } + + /** + * @return the truncated integer form of this BigFloat + */ + public BigInteger toBigInteger() { + BigInteger res = unscaled.shiftRight(fracbits - scale); + if (sign < 0) { + return res.negate(); + } + return res; + } + + /** + * @param a a BigFloat + * @return {@code round(a)} + */ + public static BigFloat round(BigFloat a) { + BigFloat b = a.copy(); + b.round(); + return b; + } + + /** + * {@code this=round(this)} + */ + public void round() { + BigFloat half = new BigFloat(fracbits, expbits, FloatKind.FINITE, +1, + BigInteger.ONE.shiftLeft(fracbits), -1); + add(half); + floor(); + } + + @Override + public int compareTo(BigFloat other) { + // this == NaN + if (isNaN()) { + if (other.isNaN()) { + return 0; + } + return 1; + } + // this != NaN + if (other.isNaN()) { + return -1; + } + if (isInfinite()) { + // this == -inf + if (sign < 0) { + if (other.isInfinite() && other.sign < 0) { + return 0; + } + return -1; + } + // this == +inf + if (other.isInfinite() && other.sign > 0) { + return 0; + } + return 1; + } + // this is finite + if (other.isInfinite()) { + return -other.sign; + } + + // other is finite + if (this.sign != other.sign) { + return this.sign; + } + + // both finite, same sign + int c = Integer.compare(this.scale, other.scale); + if (c != 0) { + return c * this.sign; + } + + return this.sign * this.unscaled.compareTo(other.unscaled); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java index 2b97ac6e6f..e0368f7074 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java @@ -20,45 +20,58 @@ import java.math.*; import ghidra.pcode.utils.Utils; import ghidra.util.SystemUtilities; -public class FloatFormat { - +public strictfp class FloatFormat { private static final int INFINITE_SCALE = -(64 * 1024); public static final BigDecimal BIG_NaN = null; - public static final BigDecimal BIG_POSITIVE_INFINITY = new BigDecimal(BigInteger.ONE, - INFINITE_SCALE); - public static final BigDecimal BIG_NEGATIVE_INFINITY = (new BigDecimal(BigInteger.ONE, - INFINITE_SCALE)).negate(); + public static final BigDecimal BIG_POSITIVE_INFINITY = + new BigDecimal(BigInteger.ONE, INFINITE_SCALE); + public static final BigDecimal BIG_NEGATIVE_INFINITY = + (new BigDecimal(BigInteger.ONE, INFINITE_SCALE)).negate(); - private static final BigInteger BIG_INT_TWO = BigInteger.valueOf(2); - private static final BigDecimal BIG_DEC_TWO = BigDecimal.valueOf(2); - private static final BigDecimal BIG_DEC_THREE = BigDecimal.valueOf(3); + static final FloatFormat JAVA_FLOAT_FORMAT = new FloatFormat(4); + static final FloatFormat JAVA_DOUBLE_FORMAT = new FloatFormat(8); - private int size; // Size of float in bytes (this format) - private int signbit_pos; // Bit position of signbit - private int frac_pos; // (lowest) bit position of fractional part - private int frac_size; // Number of bits in fractional part - private int exp_pos; // (lowest) bit position of exponent - private int exp_size; // Number of bits in exponent - private int bias; // What to add to real exponent to get encoding - private int maxexponent; // maximum stored biased/unsigned exponent - private boolean jbitimplied; // true if integer bit of 1 is assumed + private final int size; // Size of float in bytes (this format) + private final int signbit_pos; // Bit position of signbit + private final int frac_pos; // (lowest) bit position of fractional part + private final int frac_size; // Number of bits in fractional part + private final int exp_pos; // (lowest) bit position of exponent + private final int exp_size; // Number of bits in exponent + private final int bias; // What to add to real exponent to get encoding + private final int maxexponent; // maximum stored biased/unsigned exponent + private final boolean jbitimplied; // true if integer bit of 1 is assumed /** * A constant holding the largest positive finite value */ - public final BigDecimal maxValue; + public final BigFloat maxValue; /** * A constant holding the smallest positive normal value */ - public final BigDecimal minValue; + public final BigFloat minValue; - private final MathContext resultContext; + // used in string conversion + private final MathContext displayContext; public int getSize() { return size; } + /** + * Round {@code bigFloat} using this format's displayContext. + * + * @param bigFloat any BigFloat + * @return a BigDecimal rounded according to this format's displayContext + */ + public BigDecimal round(BigFloat bigFloat) { + BigDecimal bigDecimal = bigFloat.toBigDecimal(); + if (bigDecimal == null) { + return null; + } + return bigDecimal.round(displayContext); + } + // Set format for given size according to IEEE 754 standards FloatFormat(int sz) throws UnsupportedFloatFormatException { size = sz; @@ -71,7 +84,7 @@ public class FloatFormat { frac_size = 10; bias = 15; jbitimplied = true; - resultContext = new MathContext(7, RoundingMode.UP); + displayContext = new MathContext(7, RoundingMode.HALF_EVEN); } else if (size == 4) { signbit_pos = 31; @@ -81,7 +94,7 @@ public class FloatFormat { frac_size = 23; bias = 127; jbitimplied = true; - resultContext = new MathContext(7, RoundingMode.UP); + displayContext = new MathContext(7, RoundingMode.HALF_EVEN); } else if (size == 8) { signbit_pos = 63; @@ -91,7 +104,7 @@ public class FloatFormat { frac_size = 52; bias = 1023; jbitimplied = true; - resultContext = new MathContext(16, RoundingMode.UP); + displayContext = new MathContext(16, RoundingMode.HALF_EVEN); } else if (size == 16) { signbit_pos = 127; @@ -101,7 +114,7 @@ public class FloatFormat { frac_size = 112; bias = 16383; jbitimplied = true; - resultContext = new MathContext(33, RoundingMode.UP); + displayContext = new MathContext(33, RoundingMode.HALF_EVEN); } else if (size == 10) { signbit_pos = 79; @@ -111,7 +124,7 @@ public class FloatFormat { frac_size = 64; bias = 16383; jbitimplied = true; - resultContext = new MathContext(18, RoundingMode.UP); + displayContext = new MathContext(18, RoundingMode.HALF_EVEN); } else if (size == 12) { // For the Motorola 68000, extended precision, in which bits 80 to 63 are always 0. // Note that m68k internal floating point regs are 80-bits, but 96 bits are moved to/from memory. @@ -123,79 +136,56 @@ public class FloatFormat { frac_size = 64; bias = 16383; jbitimplied = true; - resultContext = new MathContext(18, RoundingMode.UP); + displayContext = new MathContext(18, RoundingMode.HALF_EVEN); } else { throw new UnsupportedFloatFormatException(sz); } maxexponent = (1 << exp_size) - 1; - // (2-(2^-frac_size))?2^bias - maxValue = - BIG_DEC_TWO.subtract(BIG_DEC_TWO.pow(-frac_size, resultContext)).multiply( - BIG_DEC_TWO.pow(bias, resultContext)); - // 2^(-bias+1) normal - // 2^(-bias) denormalized TODO: verify - minValue = BIG_DEC_TWO.pow(-bias, resultContext); + maxValue = new BigFloat(frac_size, exp_size, FloatKind.FINITE, +1, + BigInteger.ONE.shiftLeft(frac_size + 1).subtract(BigInteger.ONE), + (1 << (exp_size - 1)) - 1); + minValue = new BigFloat(frac_size, exp_size, FloatKind.FINITE, +1, BigInteger.ONE, + 2 - (1 << (exp_size - 1))); + } - // Create a double given 8-byte normalized sign, fractional, and exponent - static double createFloat(boolean sign, long mantissa, int exp) { - exp += 1023; - long bits = mantissa >>> 11; - if (exp == 0) { - bits = bits >> 1; + // Create a double given sign, 8-byte normalized mantissa, and unbiased scale + static double createFloat(boolean sgn, long mantissa, int scale) { + long exp = scale + 1023; + long bits = mantissa >>> 11;// 11 = 64 (long size) - 52 (frac size) - 1 (jbit)) + if (exp != 1) { // normal + bits &= 0xfffffffffffffL; + bits |= exp << 52; } - else { - bits = bits & 0xfffffffffffffL; - } - bits |= (long) exp << 52; - if (sign) { + if (sgn) { bits |= 0x8000000000000000L; } return Double.longBitsToDouble(bits); } - // Create a BigDecimal given sign, fractional, and exponent - static BigDecimal createFloat(boolean sign, BigInteger mantissa, int exp) { - - StringBuilder buf = new StringBuilder(); - buf.append(sign ? "-" : "+"); - buf.append(mantissa.toString()); - buf.append('e'); - buf.append(exp); - - return new BigDecimal(buf.toString()); + FloatKind extractKind(long l) { + int exp = extractExponentCode(l); + if (exp == maxexponent) { + long frac = extractFractionalCode(l); + if (frac == 0L) { + return FloatKind.INFINITE; + } + if (frac >>> (frac_size - 1) == 1) { + return FloatKind.QUIET_NAN; + } + return FloatKind.SIGNALING_NAN; + } + return FloatKind.FINITE; } - // Extract sign, fractional, and exponent from x - static FloatData extractExpSig(double x) { - long bits = Double.doubleToRawLongBits(x); - boolean sign = ((bits >> 63) != 0); - if (x == 0.0) { - return new FloatData(Floatclass.zero, sign, 0, 0); - } - if (Double.isInfinite(x)) { - return new FloatData(Floatclass.infinity, sign, 0, 0); - } - if (Double.isNaN(x)) { - return new FloatData(Floatclass.nan, sign, 0, 0); - } - int exp = (int) ((bits >> 52) & 0x7ffL); - long mantissa = - (exp == 0) ? (bits & 0xfffffffffffffL) << 1 - : (bits & 0xfffffffffffffL) | 0x10000000000000L; - mantissa <<= 11; - exp = exp - 1023; - return new FloatData(Floatclass.normalized, sign, exp, mantissa); - } - - // Extract bits encoding fractional and return normalized long value + // Extract bits encoding fractional and return un-normalized long value private long extractFractionalCode(long x) { + long mask = (1L << frac_size) - 1; x >>>= frac_pos; // Eliminate bits below - x <<= 8 * 8 - frac_size; // Align with top of long word - return x; + return x & mask; } // Extract bits encoding fractional and returned un-normalized value @@ -204,7 +194,7 @@ public class FloatFormat { return x.shiftRight(frac_pos).and(mask); } - // Extract the signbit from encoding + // Extract the signbit from encoding if size <= 8 private boolean extractSign(long x) { x >>>= signbit_pos; return ((x & 1) != 0); @@ -215,11 +205,10 @@ public class FloatFormat { return x.testBit(signbit_pos); } - // Extract bits encoding exponent + // Extract bits encoding exponent if size <= 8 private int extractExponentCode(long x) { x >>>= exp_pos; - long mask = 1; - mask = (mask << exp_size) - 1; + long mask = (1L << exp_size) - 1; return (int) (x & mask); } @@ -228,6 +217,7 @@ public class FloatFormat { return x.shiftRight(exp_pos).intValue() & maxexponent; } + // set sign bit and return the result if size <= 8 private long setSign(long x, boolean sign) { if (!sign) return x; // Assume bit is already zero @@ -237,6 +227,7 @@ public class FloatFormat { return x; } + // set sign bit and return the result private BigInteger setSign(BigInteger x, boolean sign) { if (sign) { return x.setBit(signbit_pos); @@ -244,225 +235,492 @@ public class FloatFormat { return x; } - private long getZeroEncoding(boolean sgn) { + public long getZeroEncoding(boolean sgn) { // Use IEEE 754 standard for zero encoding return setSign(0, sgn); } - private long getInfinityEncoding(boolean sgn) { + public long getInfinityEncoding(boolean sgn) { // Use IEEE 754 standard for infinity encoding long res = (long) maxexponent << exp_pos; return setSign(res, sgn); } - private BigInteger getBigInfinityEncoding(boolean sgn) { + public BigInteger getBigZeroEncoding(boolean sgn) { + BigInteger res = BigInteger.ZERO; + return setSign(res, sgn); + } + + public Object getBigZero(boolean sgn) { + return new BigFloat(frac_size, exp_size, FloatKind.FINITE, sgn ? -1 : +1, BigInteger.ZERO, + 2 - (1 << (exp_size - 1))); + } + + public BigInteger getBigInfinityEncoding(boolean sgn) { // Use IEEE 754 standard for infinity encoding BigInteger res = BigInteger.valueOf(maxexponent).shiftLeft(exp_pos); return setSign(res, sgn); } - private long getNaNEncoding(boolean sgn) { + public BigFloat getBigInfinity(boolean sgn) { + return BigFloat.infinity(frac_size, exp_size, sgn ? -1 : 1); + } + + public long getNaNEncoding(boolean sgn) { // Use IEEE 754 standard for NaN encoding long res = 1L << (frac_pos + frac_size - 1); res |= (long) maxexponent << exp_pos; return setSign(res, sgn); } - private BigInteger getBigNaNEncoding(boolean sgn) { + public BigInteger getBigNaNEncoding(boolean sgn) { // Use IEEE 754 standard for NaN encoding BigInteger res = BigInteger.ONE.shiftLeft(frac_pos + frac_size - 1); res = res.or(BigInteger.valueOf(maxexponent).shiftLeft(exp_pos)); return setSign(res, sgn); } - // Convert floating point encoding into host's double + public BigFloat getBigNaN(boolean sgn) { + return BigFloat.quietNaN(frac_size, exp_size, sgn ? -1 : 1); + } + + public BigFloat getBigFloat(float f) { + BigFloat bf = FloatFormat.toBigFloat(f); + return new BigFloat(frac_size, exp_size, bf.kind, bf.sign, + bf.unscaled.shiftLeft(frac_size - bf.fracbits), bf.scale); + } + + public BigFloat getBigFloat(double d) { + BigFloat bf = FloatFormat.toBigFloat(d); + return new BigFloat(frac_size, exp_size, bf.kind, bf.sign, + bf.unscaled.shiftLeft(frac_size - bf.fracbits), bf.scale); + } + + /** + * Decode {@code encoding} to a BigFloat using this format. + * + * NB: this method should not be used if {@link #size}>8 + * + * @param encoding the encoding + * @return the decoded value as a BigFloat + */ + public BigFloat getBigFloat(long encoding) { + boolean sgn = extractSign(encoding); + int exp = extractExponentCode(encoding); + long frac = extractFractionalCode(encoding); + FloatKind kind = extractKind(encoding); + + int scale; + BigInteger unscaled = BigInteger.valueOf(frac); + if (kind == FloatKind.FINITE) { + if (exp == 0) { // subnormal + scale = -bias + 1; + } + else { + scale = exp - bias; + unscaled = unscaled.setBit(frac_size); + } + } + else { + scale = 0; + } + return new BigFloat(frac_size, exp_size, kind, sgn ? -1 : 1, unscaled, scale); + } + + /** + * Decode {@code encoding} to a SmallFloatData using this format. + * + * NB: this method should not be used if {@link #size}>8 + * + * @param encoding the encoding + * @return the decoded value as a SmallFloatData + */ + SmallFloatData getSmallFloatData(long encoding) { + boolean sgn = extractSign(encoding); + int exp = extractExponentCode(encoding); + long frac = extractFractionalCode(encoding); + FloatKind kind = extractKind(encoding); + + int scale; + long unscaled = frac; + if (kind == FloatKind.FINITE) { + if (exp == 0) { // subnormal + scale = -bias + 1; + } + else { + scale = exp - bias; + unscaled |= 1L << frac_size; + } + } + else { + scale = 0; + } + return new SmallFloatData(frac_size, exp_size, kind, sgn ? -1 : 1, unscaled, scale); + } + + // Convert floating point encoding into host's double if size <= 8 public double getHostFloat(long encoding) { boolean sgn = extractSign(encoding); - long frac = extractFractionalCode(encoding); int exp = extractExponentCode(encoding); - boolean normal = true; + long frac = extractFractionalCode(encoding); + + boolean subnormal = false; if (exp == 0) { if (frac == 0) { // Floating point zero - // FIXME: add on sign-bit for +0 or -0 allowed by standard return sgn ? -0.0 : +0.0; } - // Number is denormalized - normal = false; + subnormal = true; } else if (exp == maxexponent) { if (frac == 0) { // Floating point infinity - // FIXME: add on sign-bit for +inf or -inf allowed by standard return sgn ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; } - // encoding is "Not a Number" NaN return Double.NaN; } - // Get "true" exponent and fractional + // Get unbiased scale and normalized mantissa exp -= bias; - if (normal && jbitimplied) { - frac >>>= 1; // Make room for 1 jbit - frac |= 0x8000000000000000L; // set bit in at top of normalized frac + long mantissa = frac << (8 * 8 - frac_size); + if (!subnormal && jbitimplied) { + mantissa >>= 1; // Make room for 1 jbit + mantissa |= 0x8000000000000000L; // set bit in at top of normalized frac } - return createFloat(sgn, frac, exp); + + return createFloat(sgn, mantissa, exp); } - // Convert floating point encoding into host's double - public BigDecimal getHostFloat(BigInteger encoding) { + public BigFloat getHostFloat(BigInteger encoding) { boolean sgn = extractSign(encoding); + int sign = sgn ? -1 : 1; BigInteger frac = extractFractionalCode(encoding); int exp = extractExponentCode(encoding); - if (exp == 0) { - if (frac.signum() == 0) { // Floating point zero - // FIXME: add on sign-bit for +0 or -0 allowed by standard - return BigDecimal.ZERO; + if (exp == 0) { // subnormals + if (frac.signum() == 0) { + return BigFloat.zero(frac_size, exp_size, sign); } - // Number is denormalized + return new BigFloat(frac_size, exp_size, FloatKind.FINITE, sign, frac, 1 - bias); } else if (exp == maxexponent) { if (frac.signum() == 0) { // Floating point infinity - // FIXME: add on sign-bit for +inf or -inf allowed by standard - return sgn ? BIG_NEGATIVE_INFINITY : BIG_POSITIVE_INFINITY; + return new BigFloat(frac_size, exp_size, FloatKind.INFINITE, sign, BigInteger.ZERO, + maxexponent); } - // encoding is "Not a Number" NaN - return BIG_NaN; + return new BigFloat(frac_size, exp_size, FloatKind.QUIET_NAN, sign, BigInteger.ZERO, + maxexponent); } - // Get "true" exponent and fractional - exp -= bias; if (jbitimplied) { - frac = frac.shiftRight(1); // Make room for 1 jbit - frac = frac.setBit(frac_size - 1); // set bit in at top frac + frac = frac.setBit(frac_size); + } + return new BigFloat(frac_size, exp_size, FloatKind.FINITE, sign, frac, exp - bias); + } + + // Convert host's double into floating point encoding if size <= 8 + public long getEncoding(double host) { + SmallFloatData value = FloatFormat.getSmallFloatData(host); + + switch (value.kind) { + case QUIET_NAN: + case SIGNALING_NAN: + return getNaNEncoding(false); + case INFINITE: + return getInfinityEncoding(value.sign < 0); + case FINITE: + break; + } + if (value.isZero()) { + return getZeroEncoding(value.sign < 0); + } + int exp; + long fraction; + + // handle the case where jbitimplied == true + if (jbitimplied) { + int lb_unscaled = leadBit(value.unscaled); + if (value.scale - value.fracbits + lb_unscaled >= 1 - bias) { + // normal case + exp = value.scale - value.fracbits + lb_unscaled + bias; + fraction = roundToLeadBit(value.unscaled, frac_size); + // if carry.. + if (leadBit(fraction) > frac_size) { + fraction = fraction >>> 1; + exp += 1; + } + fraction &= (1L << frac_size) - 1; + } + else { + // subnormal + exp = 0; + int n = value.scale - value.fracbits + lb_unscaled - 1 + bias + frac_size; + if (n < 0) { + // XXX is it possible to round up to a non-zero in this situation? + return getZeroEncoding(value.sign < 0); + } + fraction = roundToLeadBit(value.unscaled, n); // XXX round into normal case? + } + } + else { + throw new AssertionError("Unexpected jbitimplied==false"); + } + if (exp >= maxexponent) { + return getInfinityEncoding(value.sign < 0); } - MathContext expandedContext = - new MathContext(resultContext.getPrecision() * 3, resultContext.getRoundingMode()); - BigDecimal result = new BigDecimal(frac, expandedContext); - result = - result.multiply(BIG_DEC_TWO.pow(exp - frac_size + 1, expandedContext), resultContext); - result = result.stripTrailingZeros(); - if (sgn) { - result = result.negate(); + long result = ((long) exp << exp_pos) | fraction; + if (value.sign < 0) { + result |= 1L << signbit_pos; } - return result; } - // Convert host's double into floating point encoding - public long getEncoding(double host) { - - FloatData data = extractExpSig(host); // has 8-byte normalized mantissa - if (data.type == Floatclass.zero) - return getZeroEncoding(data.sign); - else if (data.type == Floatclass.infinity) - return getInfinityEncoding(data.sign); - else if (data.type == Floatclass.nan) - return getNaNEncoding(data.sign); - - int exp = data.exp; - long signif = data.mantisa; - // convert exponent and fractional to their encodings - exp += bias; - if (exp < 0) // Exponent is too small to represent - return getZeroEncoding(data.sign); - if (exp > maxexponent) // Exponent is too big to represent - return getInfinityEncoding(data.sign); - if (exp != 0 && jbitimplied) - signif <<= 1; // Cut of top bit for normal case only (which should be 1) - - long res = (signif >>> (64 - frac_size)) << frac_pos; - res |= (long) exp << exp_pos; - return setSign(res, data.sign); - } - - // Convert host's double into floating point encoding - // TODO: May not properly support denormalized values - public BigInteger getEncoding(BigDecimal value) { - - if (value == BIG_NaN) { // null value + public BigInteger getEncoding(BigFloat value) { + if (value == null) { return getBigNaNEncoding(false); } - boolean neg = false; - if (value.signum() < 0) { - neg = true; - value = value.negate(); + switch (value.kind) { + case QUIET_NAN: + case SIGNALING_NAN: + return getBigNaNEncoding(false); + case INFINITE: + return getBigInfinityEncoding(value.sign < 0); + case FINITE: + break; } - - if (value.compareTo(maxValue) >= 0) { - return getBigInfinityEncoding(neg); + if (value.isZero()) { + return getBigZeroEncoding(value.sign < 0); } + int exp; + BigInteger fraction; - if (value.compareTo(minValue) <= 0) { - return BigInteger.ZERO; - } - - BigInteger integer = value.toBigInteger(); // positive floor - BigInteger fraction = BigInteger.ZERO; - int exp = bias; - - value = value.subtract(new BigDecimal(integer)); - if (value.signum() != 0) { - for (int i = frac_size - 1; i >= 0; i--) { - // value += value - value = value.add(value); - // fraction += floor(value) * pow(2,i) {value assumed to be positive} - BigInteger floor = value.toBigInteger(); - BigDecimal valueFloor = new BigDecimal(floor); - //BigDecimal valueFloor = value.round(FLOOR); - fraction = fraction.add(floor.multiply(BIG_INT_TWO.pow(i))); - // value -= floor(value) - value = value.subtract(valueFloor); - } - } - - BigInteger fracMask1 = BigInteger.ONE.shiftLeft(frac_size - 1).subtract(BigInteger.ONE); - - while (!integer.equals(BigInteger.ONE) && exp > 0 && exp < maxexponent) { - - if (!integer.equals(BigInteger.ZERO)) { - - // fraction = (integer&1)<<(frac_size-1) + (fraction>>1) - fraction = fraction.shiftRight(1); - if (integer.testBit(0)) { - fraction = fraction.add(BigInteger.ZERO.setBit(frac_size - 1)); + // handle the case where jbitimplied == true + if (jbitimplied) { + int lb_unscaled = leadBit(value.unscaled); + if (value.scale - value.fracbits + lb_unscaled >= 1 - bias) { + // normal case + exp = value.scale - value.fracbits + lb_unscaled + bias; + fraction = roundToLeadBit(value.unscaled, frac_size); + // if carry.. + if (leadBit(fraction) > frac_size) { + fraction = fraction.shiftRight(1); + exp += 1; } - // integer = integer>>1 - integer = integer.shiftRight(1); - ++exp; + fraction = fraction.clearBit(frac_size); } else { - // integer = (fraction & bit(frac_size-1)) >> (frac_size-1) - integer = (fraction.testBit(frac_size - 1)) ? BigInteger.ONE : BigInteger.ZERO; - // fraction = (fraction & fracMask1) << 1 - fraction = fraction.and(fracMask1).shiftLeft(1); - // value += value - value = value.add(value); - // fraction += floor(value) - BigInteger floor = value.toBigInteger(); - BigDecimal valueFloor = new BigDecimal(floor); - //BigDecimal valueFloor = value.round(FLOOR); - fraction = fraction.add(floor); - // value -= floor(value) - value = value.subtract(valueFloor); - --exp; + // subnormal + exp = 0; + int n = value.scale - value.fracbits + lb_unscaled - 1 + bias + frac_size; + if (n < 0) { + // XXX is it possible to round up to a non-zero in this situation? + return getBigZeroEncoding(value.sign < 0); + } + fraction = roundToLeadBit(value.unscaled, n); } } - if (frac_pos != 0) { - fraction = fraction.shiftLeft(frac_pos); + else { + throw new AssertionError("Unexpected jbitimplied==false"); } + if (exp >= maxexponent) { + return getBigInfinityEncoding(value.sign < 0); + } + BigInteger result = BigInteger.valueOf(exp).shiftLeft(exp_pos).or(fraction); - if (neg) { + if (value.sign < 0) { result = result.setBit(signbit_pos); } return result; } + /** + * Convert an encoded value to a binary floating point representation. + * + * NB: this method should not be used if {@link #size}>8 + * + * @param encoding the encoding of a floating point value in this format + * @return a binary string representation of the encoded floating point {@code encoding} + */ + public String toBinaryString(long encoding) { + boolean sgn = extractSign(encoding); + int exp = extractExponentCode(encoding); + long frac = extractFractionalCode(encoding); + FloatKind kind = extractKind(encoding); + + switch (kind) { + case INFINITE: + if (sgn) + return "-inf"; + return "+inf"; + case QUIET_NAN: + return "qNaN"; + case SIGNALING_NAN: + return "sNaN"; + case FINITE: + break; + default: + throw new AssertionError("unexpected kind"); + + } + String binary = Long.toBinaryString(frac); + binary = "0".repeat(frac_size - binary.length()) + binary; + binary = binary.replaceAll("0*$", ""); + if (binary.isEmpty()) { + binary = "0"; + } + String s = sgn ? "-" : ""; + + if (exp == 0) { // subnormal + if (frac == 0) { + return String.format("%s0b0.0", s); + } + return String.format("%s0b0.%s * 2^%d", s, binary, -bias + 1); + } + return String.format("%s0b1.%s * 2^%d", s, binary, exp - bias); + } + + /** + * @param f a float + * @return BigFloat equal to {@code f} + */ + public static BigFloat toBigFloat(float f) { + return JAVA_FLOAT_FORMAT.getBigFloat(0xffffffffl & Float.floatToRawIntBits(f)); + } + + /** + * @param d a double + * @return BigFloat equal to {@code f} + */ + public static BigFloat toBigFloat(double d) { + return JAVA_DOUBLE_FORMAT.getBigFloat(Double.doubleToRawLongBits(d)); + } + + static SmallFloatData getSmallFloatData(double d) { + return JAVA_DOUBLE_FORMAT.getSmallFloatData(Double.doubleToRawLongBits(d)); + } + + /** + * @param f a float + * @return binary representation of {@code f} + */ + public static String toBinaryString(float f) { + return JAVA_FLOAT_FORMAT.toBinaryString(0xffffffffl & Float.floatToRawIntBits(f)); + } + + /** + * @param d a double + * @return binary representation of {@code f} + */ + public static String toBinaryString(double d) { + return JAVA_DOUBLE_FORMAT.toBinaryString(Double.doubleToRawLongBits(d)); + } + + private static int leadBit(BigInteger i) { + return i.bitLength() - 1; + } + + private static int leadBit(long l) { + return 63 - Long.numberOfLeadingZeros(l); + } + + /** + * right shift and round to nearest even or left shift to an integer with lead bit at newLeadBit. + * + * The final round up might cause a carry that propagates up, so this must be followed by a test. + * + * @param i integer representation of mantissa 1.xxxxx + * @param newLeadBit the bit position we want as a new lead bit + * @return integer representing 1.yyyy with a new lead bit position + */ + private static BigInteger roundToLeadBit(BigInteger i, int newLeadBit) { + int amt = leadBit(i) - newLeadBit; + if (amt == 0) { + return i; + } + if (amt < 0) { + return i.shiftLeft(-amt); + } + + // round to nearest even + int midbit = amt - 1; + boolean midset = i.testBit(midbit); + boolean eps = i.getLowestSetBit() < midbit; + i = i.shiftRight(amt); + boolean odd = i.testBit(0); + if (midset && (eps || odd)) { + i = i.add(BigInteger.ONE); + } + return i; + } + + private static long roundToLeadBit(long i, int newLeadBit) { + int amt = leadBit(i) - newLeadBit; + if (amt == 0) { + return i; + } + if (amt < 0) { + return i << (-amt); + } + + // round to nearest even + long midbitmask = 1L << (amt - 1); + boolean midset = (i & midbitmask) != 0; + boolean eps = ((midbitmask - 1) & i) != 0; + i >>>= amt; + boolean odd = (i & 1) != 0; + if (midset && (eps || odd)) { + i += 1; + } + return i; + } + + /** + * A small float ({@code float} and {@code double}) stand-in for {@code BigFloat} + */ + static class SmallFloatData { + final int fracbits; + final int expbits; + + final FloatKind kind; + final int sign; + + final long unscaled; + final int scale; + + /** + * Construct SmallFloat Data. + * If kind is FINITE, the value is sign*unscaled*2^(scale-fracbits) + * + * @param fracbits number of fractional bits + * @param expbits maximum number of bits in exponent + * @param kind the Kind, FINITE, INFINITE, ... + * @param sign +1 or -1 + * @param unscaled the value's mantissa + * @param scale value's scale + */ + public SmallFloatData(int fracbits, int expbits, FloatKind kind, int sign, long unscaled, + int scale) { + this.fracbits = fracbits; + this.expbits = expbits; + this.kind = kind; + this.sign = sign; + this.unscaled = unscaled; + this.scale = scale; + } + + public boolean isZero() { + return this.kind == FloatKind.FINITE && unscaled == 0L; + } + + } + // Currently we emulate floating point operations on the target // By converting the encoding to the host's encoding and then // performing the operation using the host's floating point unit // then the host's encoding is converted back to the targets encoding + // each operation is implemented for both encoding, long and BigInteger. + // The long methods should not be used when size>8. + public long opEqual(long a, long b) { // a == b double val1 = getHostFloat(a); double val2 = getHostFloat(b); @@ -471,12 +729,12 @@ public class FloatFormat { } public BigInteger opEqual(BigInteger a, BigInteger b) { // a == b - BigDecimal val1 = getHostFloat(a); - BigDecimal val2 = getHostFloat(b); - if (val1 == BIG_NaN || val2 == BIG_NaN) { + BigFloat fa = getHostFloat(a); + BigFloat fb = getHostFloat(b); + if (fa.isNaN() || fb.isNaN()) { return BigInteger.ZERO; } - BigInteger res = SystemUtilities.isEqual(val1, val2) ? BigInteger.ONE : BigInteger.ZERO; + BigInteger res = SystemUtilities.isEqual(fa, fb) ? BigInteger.ONE : BigInteger.ZERO; return res; } @@ -488,12 +746,12 @@ public class FloatFormat { } public BigInteger opNotEqual(BigInteger a, BigInteger b) { // a != b - BigDecimal val1 = getHostFloat(a); - BigDecimal val2 = getHostFloat(b); - if (val1 == BIG_NaN || val2 == BIG_NaN) { + BigFloat fa = getHostFloat(a); + BigFloat fb = getHostFloat(b); + if (fa.isNaN() | fb.isNaN()) { return BigInteger.ONE; } - BigInteger res = SystemUtilities.isEqual(val1, val2) ? BigInteger.ZERO : BigInteger.ONE; + BigInteger res = SystemUtilities.isEqual(fa, fb) ? BigInteger.ZERO : BigInteger.ONE; return res; } @@ -505,12 +763,9 @@ public class FloatFormat { } public BigInteger opLess(BigInteger a, BigInteger b) { // a < b - BigDecimal val1 = getHostFloat(a); - BigDecimal val2 = getHostFloat(b); - if (val1 == BIG_NaN || val2 == BIG_NaN) { - return BigInteger.ZERO; - } - BigInteger res = (val1.compareTo(val2) < 0) ? BigInteger.ONE : BigInteger.ZERO; + BigFloat fa = getHostFloat(a); + BigFloat fb = getHostFloat(b); + BigInteger res = (fa.compareTo(fb) < 0) ? BigInteger.ONE : BigInteger.ZERO; return res; } @@ -522,16 +777,13 @@ public class FloatFormat { } public BigInteger opLessEqual(BigInteger a, BigInteger b) { // a <= b - BigDecimal val1 = getHostFloat(a); - BigDecimal val2 = getHostFloat(b); - if (val1 == BIG_NaN || val2 == BIG_NaN) { - return BigInteger.ZERO; - } - BigInteger res = (val1.compareTo(val2) <= 0) ? BigInteger.ONE : BigInteger.ZERO; + BigFloat fa = getHostFloat(a); + BigFloat fb = getHostFloat(b); + BigInteger res = (fa.compareTo(fb) <= 0) ? BigInteger.ONE : BigInteger.ZERO; return res; } - // true is a is "not a number" + // true if a is "not a number" public long opNan(long a) { double val = getHostFloat(a); long res = Double.isNaN(val) ? 1 : 0; @@ -539,8 +791,8 @@ public class FloatFormat { } public BigInteger opNan(BigInteger a) { - BigDecimal val = getHostFloat(a); - BigInteger res = (val == BIG_NaN) ? BigInteger.ONE : BigInteger.ZERO; + BigFloat val = getHostFloat(a); + BigInteger res = (val.isNaN()) ? BigInteger.ONE : BigInteger.ZERO; return res; } @@ -551,24 +803,10 @@ public class FloatFormat { } public BigInteger opAdd(BigInteger a, BigInteger b) { // a + b - BigDecimal val1 = getHostFloat(a); - BigDecimal val2 = getHostFloat(b); - if (val1 == BIG_NaN || val2 == BIG_NaN) { - return getBigNaNEncoding(false); - } - if (val1 == BIG_POSITIVE_INFINITY) { - if (val2 == BIG_NEGATIVE_INFINITY) { - return getBigNaNEncoding(false); - } - return a; - } - if (val1 == BIG_NEGATIVE_INFINITY) { - if (val2 == BIG_POSITIVE_INFINITY) { - return getBigNaNEncoding(false); - } - return a; - } - return getEncoding(val1.add(val2, resultContext)); + BigFloat fa = getHostFloat(a); + BigFloat fb = getHostFloat(b); + fa.add(fb); + return getEncoding(fa); } public long opSub(long a, long b) { // a - b @@ -578,24 +816,10 @@ public class FloatFormat { } public BigInteger opSub(BigInteger a, BigInteger b) { // a - b - BigDecimal val1 = getHostFloat(a); - BigDecimal val2 = getHostFloat(b); - if (val1 == BIG_NaN || val2 == BIG_NaN) { - return getBigNaNEncoding(false); - } - if (val1 == BIG_POSITIVE_INFINITY) { - if (val2 == BIG_POSITIVE_INFINITY) { - return getBigNaNEncoding(false); - } - return a; - } - if (val1 == BIG_NEGATIVE_INFINITY) { - if (val2 == BIG_NEGATIVE_INFINITY) { - return getBigNaNEncoding(false); - } - return a; - } - return getEncoding(val1.subtract(val2, resultContext)); + BigFloat fa = getHostFloat(a); + BigFloat fb = getHostFloat(b); + fa.sub(fb); + return getEncoding(fa); } public long opDiv(long a, long b) { // a / b @@ -605,18 +829,10 @@ public class FloatFormat { } public BigInteger opDiv(BigInteger a, BigInteger b) { // a / b - BigDecimal val1 = getHostFloat(a); - BigDecimal val2 = getHostFloat(b); - if (val1 == BIG_NaN || val2 == BIG_NaN) { - return getBigNaNEncoding(false); - } - if (val2.signum() == 0) { - if (val1.signum() == 0) { - return getBigNaNEncoding(false); - } - return getBigInfinityEncoding(val1.signum() < 0); - } - return getEncoding(val1.divide(val2, resultContext)); + BigFloat fa = getHostFloat(a); + BigFloat fb = getHostFloat(b); + fa.div(fb); + return getEncoding(fa); } public long opMult(long a, long b) { // a * b @@ -626,12 +842,10 @@ public class FloatFormat { } public BigInteger opMult(BigInteger a, BigInteger b) { // a * b - BigDecimal val1 = getHostFloat(a); - BigDecimal val2 = getHostFloat(b); - if (val1 == BIG_NaN || val2 == BIG_NaN) { - return getBigNaNEncoding(false); - } - return getEncoding(val1.multiply(val2, resultContext)); + BigFloat fa = getHostFloat(a); + BigFloat fb = getHostFloat(b); + fa.mul(fb); + return getEncoding(fa); } public long opNeg(long a) { // -a @@ -640,11 +854,9 @@ public class FloatFormat { } public BigInteger opNeg(BigInteger a) { - BigDecimal val = getHostFloat(a); - if (val == BIG_NaN) { - return a; - } - return getEncoding(val.negate()); + BigFloat fa = getHostFloat(a); + fa.negate(); + return getEncoding(fa); } public long opAbs(long a) { // absolute value of a @@ -653,11 +865,9 @@ public class FloatFormat { } public BigInteger opAbs(BigInteger a) { - BigDecimal val = getHostFloat(a); - if (val == BIG_NaN) { - return a; - } - return getEncoding(val.abs()); + BigFloat fa = getHostFloat(a); + fa.abs(); + return getEncoding(fa); } public long opSqrt(long a) { // square root of a @@ -666,34 +876,9 @@ public class FloatFormat { } public BigInteger opSqrt(BigInteger a) { - BigDecimal val = getHostFloat(a); - if (val == BIG_NaN) { - return a; - } - int signum = val.signum(); - if (signum < 0) { - return getBigNaNEncoding(false); - } - if (signum == 0) { - return BigInteger.ZERO; - } - - int scale = resultContext.getPrecision() * 2; - - BigDecimal result = val.divide(BIG_DEC_THREE, scale, BigDecimal.ROUND_HALF_EVEN); - BigDecimal lastResult = BigDecimal.ZERO; - - for (int i = 0; i < 50; i++) { - result = - val.add(result.multiply(result)).divide(result.multiply(BIG_DEC_TWO), scale, - BigDecimal.ROUND_HALF_EVEN); - if (result.compareTo(lastResult) == 0) { - break; - } - lastResult = result; - } - - return getEncoding(result); + BigFloat fa = getHostFloat(a); + fa.sqrt(); + return getEncoding(fa); } // convert integer to floating point @@ -711,8 +896,7 @@ public class FloatFormat { else { a = Utils.convertToUnsignedValue(a, sizein); } - BigDecimal val = new BigDecimal(a); - return getEncoding(val); + return getEncoding(BigFloat.valueOf(frac_size, exp_size, a)); } public long opFloat2Float(long a, FloatFormat outformat) { // convert between floating @@ -722,11 +906,8 @@ public class FloatFormat { } public BigInteger opFloat2Float(BigInteger a, FloatFormat outformat) { // convert between floating - BigDecimal val = getHostFloat(a); - if (val == BIG_NaN) { - return outformat.getBigNaNEncoding(false); - } - return outformat.getEncoding(val); + BigFloat fa = getHostFloat(a); + return outformat.getEncoding(fa); } public long opTrunc(long a, int sizeout) { // convert floating point to integer @@ -737,20 +918,20 @@ public class FloatFormat { } public BigInteger opTrunc(BigInteger a, int sizeout) { // convert floating point to integer - BigDecimal val = getHostFloat(a); - if (val == BIG_NaN) { + BigFloat fa = getHostFloat(a); + if (fa.isNaN()) { return BigInteger.ZERO; // consistent with Java Double->Long behavior } - if (val == BIG_POSITIVE_INFINITY) { - // max positive int - return BigInteger.ONE.shiftLeft((8 * size)).subtract(BigInteger.ONE).shiftRight(1); - } - if (val == BIG_NEGATIVE_INFINITY) { + if (fa.isInfinite()) { + if (fa.sign > 0) { + // max positive int + return BigInteger.ONE.shiftLeft((8 * size)).subtract(BigInteger.ONE).shiftRight(1); + } + // max negative int return BigInteger.ONE.shiftLeft((8 * size) - 1).negate(); } - BigInteger res = val.toBigInteger(); // Convert to integer - return res; + return fa.toBigInteger(); } public long opCeil(long a) { // integer ceiling of a @@ -759,15 +940,9 @@ public class FloatFormat { } public BigInteger opCeil(BigInteger a) { // integer ceiling of a - BigDecimal val = getHostFloat(a); - if (val == BIG_NaN) { - return a; - } - BigInteger intval = val.toBigInteger(); - if (intval.signum() > 0 && !val.unscaledValue().equals(intval)) { - intval = intval.add(BigInteger.ONE); - } - return getEncoding(new BigDecimal(intval)); + BigFloat fa = getHostFloat(a); + fa.ceil(); + return getEncoding(fa); } public long opFloor(long a) { // integer floor of a @@ -775,25 +950,10 @@ public class FloatFormat { return getEncoding(Math.floor(val)); } - private BigInteger floor(BigDecimal val) { - if (val.signum() < 0) { - try { - return val.toBigIntegerExact(); - } - catch (ArithmeticException e) { - return val.toBigInteger().subtract(BigInteger.ONE); - } - } - return val.toBigInteger(); - } - public BigInteger opFloor(BigInteger a) { // integer floor of a - BigDecimal val = getHostFloat(a); - if (val == BIG_NaN) { - return a; - } - BigInteger intval = floor(val); - return getEncoding(new BigDecimal(intval)); + BigFloat fa = getHostFloat(a); + fa.floor(); + return getEncoding(fa); } public long opRound(long a) { // nearest integer to a @@ -802,27 +962,9 @@ public class FloatFormat { } public BigInteger opRound(BigInteger a) { // nearest integer to a - BigDecimal val = getHostFloat(a); - if (val == BIG_NaN) { - return a; - } - BigInteger intval = floor(val.add(BigDecimal.valueOf(0.5d), resultContext)); - return getEncoding(new BigDecimal(intval)); + BigFloat fa = getHostFloat(a); + fa.round(); + return getEncoding(fa); } - static class FloatData { - - final Floatclass type; - final boolean sign; - final int exp; - final long mantisa; - - public FloatData(Floatclass type, boolean sign, int exp, long mantisa) { - this.type = type; - this.sign = sign; - this.exp = exp; - this.mantisa = mantisa; - } - - } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/Floatclass.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatKind.java similarity index 84% rename from Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/Floatclass.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatKind.java index 39e8e990c4..d0b08be3d6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/Floatclass.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatKind.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +15,9 @@ */ package ghidra.pcode.floatformat; - -public enum Floatclass { - normalized, - infinity, - zero, - nan, - denormalized; +enum FloatKind { + FINITE, /* includes both normal and subnormal */ + INFINITE, + QUIET_NAN, + SIGNALING_NAN; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractFloatDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractFloatDataType.java index 61ec3e1fe9..c316674273 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractFloatDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractFloatDataType.java @@ -85,8 +85,7 @@ public abstract class AbstractFloatDataType extends BuiltIn { return doubleValue; } BigInteger value = Utils.bytesToBigInteger(bytes, len, buf.isBigEndian(), false); - BigDecimal decValue = floatFormat.getHostFloat(value); - // TODO: adjust scale for improved display value ?? + BigDecimal decValue = floatFormat.round(floatFormat.getHostFloat(value)); return decValue; } catch (UnsupportedFloatFormatException e) { @@ -197,7 +196,8 @@ public abstract class AbstractFloatDataType extends BuiltIn { } for (int size : floatMap.keySet()) { if (!newFloatMap.containsKey(size)) { - newFloatMap.put(size, (AbstractFloatDataType) floatMap.get(size).clone(dtm)); + newFloatMap.put(size, + (AbstractFloatDataType) floatMap.get(size).clone(dtm)); } } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/BigFloatTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/BigFloatTest.java new file mode 100644 index 0000000000..7645cc0f8e --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/BigFloatTest.java @@ -0,0 +1,361 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.pcode.floatformat; + +import static org.junit.Assert.*; + +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.Assert; +import org.junit.Test; + +import generic.test.AbstractGenericTest; + +public class BigFloatTest extends AbstractGenericTest { + public BigFloatTest() { + super(); + } + + @Test + public void testIEEEFloatRepresentation() { + Assert.assertEquals("0b0.0", FloatFormat.toBinaryString(0.0f)); + Assert.assertEquals("0b1.0 * 2^0", FloatFormat.toBinaryString(1.0f)); + Assert.assertEquals("0b1.0 * 2^1", FloatFormat.toBinaryString(2.0f)); + Assert.assertEquals("0b1.0 * 2^-1", FloatFormat.toBinaryString(0.5f)); + Assert.assertEquals("-0b1.0 * 2^1", FloatFormat.toBinaryString(-2.0f)); + } + + @Test + public void testIEEEFloatAsBigFloat() { + Assert.assertEquals(FloatFormat.toBigFloat(0.0f).toBinaryString(), + FloatFormat.toBinaryString(0.0f)); + Assert.assertEquals(FloatFormat.toBigFloat(1.0f).toBinaryString(), + FloatFormat.toBinaryString(1.0f)); + Assert.assertEquals(FloatFormat.toBigFloat(2.0f).toBinaryString(), + FloatFormat.toBinaryString(2.0f)); + Assert.assertEquals(FloatFormat.toBigFloat(0.5f).toBinaryString(), + FloatFormat.toBinaryString(0.5f)); + Assert.assertEquals(FloatFormat.toBigFloat(-2.0f).toBinaryString(), + FloatFormat.toBinaryString(-2.0f)); + } + + @Test + public void testIEEEFloatAsBigFloatRandom() { + Random rand = new Random(1); + for (int i = 0; i < 100; ++i) { + float f = Float.intBitsToFloat(rand.nextInt()); + Assert.assertEquals(FloatFormat.toBigFloat(f).toBinaryString(), + FloatFormat.toBinaryString(f)); + } + } + + @Test + public void testIEEEDoubleRepresentation() { + Assert.assertEquals("0b0.0", FloatFormat.toBinaryString(0.0)); + Assert.assertEquals("0b1.0 * 2^0", FloatFormat.toBinaryString(1.0)); + Assert.assertEquals("0b1.0 * 2^1", FloatFormat.toBinaryString(2.0)); + Assert.assertEquals("0b1.0 * 2^-1", FloatFormat.toBinaryString(0.5)); + Assert.assertEquals("-0b1.0 * 2^1", FloatFormat.toBinaryString(-2.0)); + } + + @Test + public void testIEEEDoubleAsBigFloat() { + Assert.assertEquals(FloatFormat.toBigFloat(0.0).toBinaryString(), + FloatFormat.toBinaryString(0.0)); + Assert.assertEquals(FloatFormat.toBigFloat(1.0).toBinaryString(), + FloatFormat.toBinaryString(1.0)); + Assert.assertEquals(FloatFormat.toBigFloat(2.0).toBinaryString(), + FloatFormat.toBinaryString(2.0)); + Assert.assertEquals(FloatFormat.toBigFloat(0.5).toBinaryString(), + FloatFormat.toBinaryString(0.5)); + Assert.assertEquals(FloatFormat.toBigFloat(-2.0).toBinaryString(), + FloatFormat.toBinaryString(-2.0)); + } + + @Test + public void testIEEEDoubleAsBigFloatRandom() { + Random rand = new Random(1); + for (int i = 0; i < 100; ++i) { + double d = Double.longBitsToDouble(rand.nextLong()); + Assert.assertEquals(FloatFormat.toBigFloat(d).toBinaryString(), + FloatFormat.toBinaryString(d)); + } + } + + interface UnaryProc { + void apply(T a); + } + + interface UnaryOp { + T apply(T a); + } + + interface BinaryProc { + void apply(T a, T b); + } + + interface BinaryOp { + T apply(T a, T b); + } + + // used for testing one-argument operations + final static int NUM_RANDOM_TEST_VALUES_UNARY = 1000; + // used for each operand of two-argument operations + final static int NUM_RANDOM_TEST_VALUES_BINARY = 100; + + final static List testFloatList; + final static List testFloatShortList; + static { + Random rand = new Random(1); + + // @formatter:off + List specialValues = + List.of( + -0.0f, 0.0f, + -1.0f, 1.0f, + -Float.MIN_VALUE, Float.MIN_VALUE, + -Float.MAX_VALUE, Float.MAX_VALUE, + -Float.MIN_NORMAL - Float.MIN_VALUE, -Float.MIN_NORMAL, -Float.MIN_NORMAL + Float.MIN_VALUE, + Float.MIN_NORMAL - Float.MIN_VALUE, Float.MIN_NORMAL, Float.MIN_NORMAL + Float.MIN_VALUE, + Float.NaN, + Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY); + // @formatter:on + Stream randStream = Stream.generate(rand::nextInt) + .limit(NUM_RANDOM_TEST_VALUES_UNARY) + .map(Float::intBitsToFloat); + + testFloatList = Stream.concat(specialValues.stream(), randStream) + .collect(Collectors.toUnmodifiableList()); + testFloatShortList = + testFloatList.subList(0, specialValues.size() + NUM_RANDOM_TEST_VALUES_BINARY); + } + + final static List testDoubleList; + final static List testDoubleShortList; + static { + Random rand = new Random(1); + + // @formatter:off + List specialValues = + List.of( + -0.0, 0.0, + -1.0, 1.0, + -Double.MIN_VALUE, Double.MIN_VALUE, + -Double.MAX_VALUE, Double.MAX_VALUE, + -Double.MIN_NORMAL - Double.MIN_VALUE, -Double.MIN_NORMAL, -Double.MIN_NORMAL + Double.MIN_VALUE, + Double.MIN_NORMAL - Double.MIN_VALUE, Double.MIN_NORMAL, Double.MIN_NORMAL + Double.MIN_VALUE, + Double.NaN, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + // @formatter:on + + Stream randStream = Stream.generate(rand::nextLong) + .limit(NUM_RANDOM_TEST_VALUES_UNARY) + .map(Double::longBitsToDouble); + + testDoubleList = Stream.concat(specialValues.stream(), randStream) + .collect(Collectors.toUnmodifiableList()); + testDoubleShortList = + testDoubleList.subList(0, specialValues.size() + NUM_RANDOM_TEST_VALUES_BINARY); + } + + public void unaryDoubleOpTest(UnaryOp op, UnaryProc bproc) { + int i = 0; + for (double fa : testDoubleList) { + BigFloat bfa = FloatFormat.toBigFloat(fa); + + double fb = op.apply(fa); + bproc.apply(bfa); + + assertEquals("case #" + Integer.toString(i), Double.isNaN(fb), bfa.isNaN()); + if (!Double.isNaN(fb)) { + assertEquals("case #" + Integer.toString(i), + FloatFormat.toBinaryString(op.apply(fa)), bfa.toBinaryString()); + } + ++i; + } + } + + public void binaryDoubleOpTest(BinaryOp op, BinaryProc bproc) { + int i = 0; + for (double fa : testDoubleShortList) { + int j = 0; + for (double fb : testDoubleShortList) { + BigFloat bfa = FloatFormat.toBigFloat(fa); + BigFloat bfb = FloatFormat.toBigFloat(fb); + + double fc = op.apply(fa, fb); + bproc.apply(bfa, bfb); + + assertEquals(String.format("case #%d,%d", i, j), Double.isNaN(fc), bfa.isNaN()); + if (!Double.isNaN(fc)) { + assertEquals(String.format("case #%d,%d", i, j), FloatFormat.toBinaryString(fc), + bfa.toBinaryString()); + } + + ++j; + } + + ++i; + } + } + + public void unaryFloatOpTest(UnaryOp op, UnaryProc bproc) { + int i = 0; + for (float fa : testFloatList) { + BigFloat bfa = FloatFormat.toBigFloat(fa); + + float fb = op.apply(fa); + bproc.apply(bfa); + assertEquals("case #" + Integer.toString(i), Float.isNaN(fb), bfa.isNaN()); + if (!Float.isNaN(fb)) { + assertEquals("case #" + Integer.toString(i), FloatFormat.toBinaryString(fb), + bfa.toBinaryString()); + } + + ++i; + } + } + + public void binaryFloatOpTest(BinaryOp op, BinaryProc bproc) { + int i = 0; + for (float fa : testFloatShortList) { + int j = 0; + for (float fb : testFloatShortList) { + BigFloat bfa = FloatFormat.toBigFloat(fa); + BigFloat bfb = FloatFormat.toBigFloat(fb); + + float fc = op.apply(fa, fb); + bproc.apply(bfa, bfb); + + assertEquals(String.format("case #%d,%d", i, j), Float.isNaN(fc), bfa.isNaN()); + if (!Float.isNaN(fc)) { + assertEquals(String.format("case #%d,%d", i, j), FloatFormat.toBinaryString(fc), + bfa.toBinaryString()); + } + + ++j; + } + + ++i; + } + } + + @Test + public void testFloatAdd() { + binaryFloatOpTest((a, b) -> a + b, (a, b) -> a.add(b)); + } + + @Test + public void testFloatSubstract() { + binaryFloatOpTest((a, b) -> a - b, (a, b) -> a.sub(b)); + } + + @Test + public void testFloatMultiply() { + binaryFloatOpTest((a, b) -> a * b, (a, b) -> a.mul(b)); + } + + @Test + public void testFloatDivide() { + binaryFloatOpTest((a, b) -> a / b, (a, b) -> a.div(b)); + } + + @Test + public void testFloatCompare() { + int i = 0; + for (float a : testFloatShortList) { + int j = 0; + BigFloat fa = FloatFormat.toBigFloat(a); + for (float b : testFloatShortList) { + BigFloat fb = FloatFormat.toBigFloat(b); + assertEquals(String.format("case #%d,%d", i, j), Float.compare(a, b), + fa.compareTo(fb)); + ++j; + } + ++i; + } + } + + @Test + public void testFloatSqrt() { + unaryFloatOpTest(a -> (float) Math.sqrt(a), a -> a.sqrt()); + } + + @Test + public void testFloatFloor() { + unaryFloatOpTest(a -> (float) Math.floor(a), a -> a.floor()); + } + + @Test + public void testFloatCeil() { + unaryFloatOpTest(a -> (float) Math.ceil(a), a -> a.ceil()); + } + + @Test + public void testDoubleAdd() { + binaryDoubleOpTest((a, b) -> a + b, (a, b) -> a.add(b)); + } + + @Test + public void testDoubleSubstract() { + binaryDoubleOpTest((a, b) -> a - b, (a, b) -> a.sub(b)); + } + + @Test + public void testDoubleMultiply() { + binaryDoubleOpTest((a, b) -> a * b, (a, b) -> a.mul(b)); + } + + @Test + public void testDoubleDivide() { + binaryDoubleOpTest((a, b) -> a / b, (a, b) -> a.div(b)); + } + + @Test + public void testDoubleCompare() { + int i = 0; + for (double a : testDoubleShortList) { + int j = 0; + BigFloat fa = FloatFormat.toBigFloat(a); + for (double b : testDoubleShortList) { + BigFloat fb = FloatFormat.toBigFloat(b); + assertEquals(String.format("case #%d,%d", i, j), Double.compare(a, b), + fa.compareTo(fb)); + ++j; + } + ++i; + } + } + + @Test + public void testDoubleSqrt() { + unaryDoubleOpTest(a -> Math.sqrt(a), a -> a.sqrt()); + } + + @Test + public void testDoubleFloor() { + unaryDoubleOpTest(a -> Math.floor(a), a -> a.floor()); + } + + @Test + public void testDoubleCeil() { + unaryDoubleOpTest(a -> Math.ceil(a), a -> a.ceil()); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java index 1664798087..cd0f805b02 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java @@ -15,18 +15,16 @@ */ package ghidra.pcode.floatformat; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; -import java.math.BigDecimal; -import java.math.BigInteger; +import java.math.*; +import java.util.Random; -import org.junit.Assert; -import org.junit.Test; +import org.junit.*; import generic.test.AbstractGenericTest; -import ghidra.pcode.floatformat.FloatFormat.FloatData; -public class FloatFormatTest extends AbstractGenericTest { +public strictfp class FloatFormatTest extends AbstractGenericTest { public FloatFormatTest() { super(); @@ -34,25 +32,225 @@ public class FloatFormatTest extends AbstractGenericTest { @Test public void testCreateFloat() { - double x = 4.5; - FloatData data = FloatFormat.extractExpSig(x); - double y = FloatFormat.createFloat(data.sign, data.mantisa, data.exp); - Assert.assertEquals(x, y, 0); + int i = 0; + for (double x : BigFloatTest.testDoubleList) { + if (!Double.isFinite(x)) { + continue; + } + FloatFormat.SmallFloatData data = FloatFormat.getSmallFloatData(x); + double y = FloatFormat.createFloat(data.sign < 0, + data.unscaled << (64 - data.fracbits - 1), data.scale); + Assert.assertEquals("case #" + Integer.toString(i), x, y, 0); + ++i; + } + } - x = -4.5; - data = FloatFormat.extractExpSig(x); - y = FloatFormat.createFloat(data.sign, data.mantisa, data.exp); - Assert.assertEquals(x, y, 0); + @Test + public void testGetEncodingMinval() { + FloatFormat ff = new FloatFormat(4); - x = 0.00000000000000000000000045; - data = FloatFormat.extractExpSig(x); - y = FloatFormat.createFloat(data.sign, data.mantisa, data.exp); - Assert.assertEquals(x, y, 0); + float minFloat = Float.MIN_VALUE; - x = -0.000000000000000000000000045; - data = FloatFormat.extractExpSig(x); - y = FloatFormat.createFloat(data.sign, data.mantisa, data.exp); - Assert.assertEquals(x, y, 0); + double d0 = minFloat; + + BigFloat minFloatBig4 = FloatFormat.toBigFloat(minFloat); + Assert.assertTrue(!minFloatBig4.isNaN() && !minFloatBig4.isNormal()); + + // doubles have plenty of room at the bottom, so the mininum float is normal + BigFloat minFloatBig8 = FloatFormat.toBigFloat(d0); + Assert.assertTrue(minFloatBig8.isNormal()); + + long trueEncoding = Float.floatToRawIntBits(minFloat); + long ffEncoding = ff.getEncoding(d0); + long ffBigEncoding4 = ff.getEncoding(minFloatBig4).longValue(); + long ffBigEncoding8 = ff.getEncoding(minFloatBig8).longValue(); + + Assert.assertEquals(trueEncoding, ffEncoding); + Assert.assertEquals(ff.minValue, minFloatBig4); + Assert.assertNotEquals(ff.minValue, minFloatBig8); // different precision implies different floats + Assert.assertEquals(trueEncoding, ffBigEncoding4); + Assert.assertEquals(trueEncoding, ffBigEncoding8); + } + + @Test + public void testGetEncodingMaxval() { + FloatFormat ff = new FloatFormat(4); + + float maxFloat = Float.MAX_VALUE; + + double d0 = maxFloat; + + BigFloat maxFloatBig4 = FloatFormat.toBigFloat(maxFloat); + Assert.assertTrue(maxFloatBig4.isNormal()); + + BigFloat maxFloatBig8 = FloatFormat.toBigFloat(d0); + Assert.assertTrue(maxFloatBig8.isNormal()); + + long trueEncoding = Float.floatToRawIntBits(maxFloat); + long ffEncoding = ff.getEncoding(d0); + long ffBigEncoding4 = ff.getEncoding(maxFloatBig4).longValue(); + long ffBigEncoding8 = ff.getEncoding(maxFloatBig8).longValue(); + + Assert.assertEquals(trueEncoding, ffEncoding); + Assert.assertEquals(ff.maxValue, maxFloatBig4); + Assert.assertNotEquals(ff.maxValue, maxFloatBig8); // different precision implies different floats + Assert.assertEquals(trueEncoding, ffBigEncoding4); + Assert.assertEquals(trueEncoding, ffBigEncoding8); + } + + @Test + public void testGetEncodingRoundToNearestEven() { + FloatFormat ff = new FloatFormat(4); + + // this test is a verbose exposition of the more complete assertDoubleMidpointRound + + // IEEE754 recommends "round to nearest even" for binary formats, like single and double + // precision floating point. It rounds to the nearest integer (significand) when unambiguous, + // and to the nearest even on the midpoint. + + // There are 52 bits of significand in a double and 23 in a float. + // Below we construct a sequence of double precision values to demonstrate each case + // in rounding, + + // d0 - zeros in low 29 bits, round down + // d1 - on the rounding midpoint with integer even integer part, round down + // d2 - just above the midpoint, round up + double d0 = Double.longBitsToDouble(0x4010000000000000L); + double d1 = Double.longBitsToDouble(0x4010000010000000L); + double d2 = Double.longBitsToDouble(0x4010000010000001L); + + // d3 - zeros in low 29 bits, round down + // d4 - on the rounding midpoint with integer part odd, round up + // d5 - just above the midpoint, round up + double d3 = Double.longBitsToDouble(0x4010000020000000L); + double d4 = Double.longBitsToDouble(0x4010000030000000L); + double d5 = Double.longBitsToDouble(0x4010000030000001L); + + float f0 = (float) d0; + float f1 = (float) d1; + float f2 = (float) d2; + float f3 = (float) d3; + float f4 = (float) d4; + float f5 = (float) d5; + + long e0 = ff.getEncoding(d0); + long e1 = ff.getEncoding(d1); + long e2 = ff.getEncoding(d2); + long e3 = ff.getEncoding(d3); + long e4 = ff.getEncoding(d4); + long e5 = ff.getEncoding(d5); + + Assert.assertEquals(Float.floatToRawIntBits(f0), e0); + Assert.assertEquals(Float.floatToRawIntBits(f1), e1); + Assert.assertEquals(Float.floatToRawIntBits(f2), e2); + Assert.assertEquals(Float.floatToRawIntBits(f3), e3); + Assert.assertEquals(Float.floatToRawIntBits(f4), e4); + Assert.assertEquals(Float.floatToRawIntBits(f5), e5); + + Assert.assertEquals(e0, e1); + Assert.assertNotEquals(e1, e2); + + Assert.assertNotEquals(e3, e4); + Assert.assertEquals(e4, e5); + } + + static protected long makeDoubleFloat(boolean neg, int exp, int float_frac) { + long l = neg ? 1L << 63 : 0L; + l |= (1023L + exp) << 52; + l |= ((long) float_frac) << (52 - 23); + return l; + } + + // create a native double at the rounding middle point for the conversion to float. + // assert that the FloatFormat conversion and cast to float produce the same thing + protected void assertDoubleMidpointRound(boolean neg, int exp, int float_frac) { + long insignif = 1L << (52 - 23 - 1); + + long candidate = makeDoubleFloat(neg, exp, float_frac); + long lmid = candidate + insignif; + + double dmid = Double.longBitsToDouble(lmid); + + // round from double to single precision + FloatFormat ff = new FloatFormat(4); + int actual = (int) ff.getEncoding(dmid); + + float fmid = (float) dmid; + int expected = Float.floatToRawIntBits(fmid); + + Assert.assertEquals(String.format("expected %08x != actual %08x", expected, actual), + expected, actual); + } + + protected void assertBigMidpointRound(boolean neg, int exp, int float_frac) { + long insignif = 1L << (52 - 23 - 1); + + long candidate = makeDoubleFloat(neg, exp, float_frac); + long lmid = candidate + insignif; + + double dmid = Double.longBitsToDouble(lmid); + BigFloat bdmid = FloatFormat.toBigFloat(dmid); + + // round from double to single precision + FloatFormat ff = new FloatFormat(4); + int actual = ff.getEncoding(bdmid).intValue(); + + float fmid = (float) dmid; + int expected = Float.floatToRawIntBits(fmid); + + Assert.assertEquals(String.format("expected %08x != actual %08x", expected, actual), + expected, actual); + } + + @Test + public strictfp void testDoubleRoundAtMidpoint() { + // test even and odd float significands at extremes + assertDoubleMidpointRound(false, 1, 1); + assertDoubleMidpointRound(false, 1, 2); + assertDoubleMidpointRound(false, 1, (1 << 23) - 1); + assertDoubleMidpointRound(false, 1, (1 << 23) - 2); + + assertDoubleMidpointRound(false, 120, 1); + assertDoubleMidpointRound(false, 120, 2); + assertDoubleMidpointRound(false, 120, (1 << 23) - 1); + assertDoubleMidpointRound(false, 120, (1 << 23) - 2); + + assertDoubleMidpointRound(false, -120, 1); + assertDoubleMidpointRound(false, -120, 2); + assertDoubleMidpointRound(false, -120, (1 << 23) - 1); + assertDoubleMidpointRound(false, -120, (1 << 23) - 2); + + assertDoubleMidpointRound(true, 1, 1); + assertDoubleMidpointRound(true, 1, 2); + assertDoubleMidpointRound(true, 1, (1 << 23) - 1); + assertDoubleMidpointRound(true, 1, (1 << 23) - 2); + + // overflow + assertDoubleMidpointRound(false, Float.MAX_EXPONENT, (1 << 23) - 1); + } + + @Test + public strictfp void testBigRoundAtMidpoint() { + // test even and odd float significands at extremes + assertBigMidpointRound(false, 1, 1); + assertBigMidpointRound(false, 1, 2); + assertBigMidpointRound(false, 1, (1 << 23) - 1); + assertBigMidpointRound(false, 1, (1 << 23) - 2); + + assertBigMidpointRound(false, 120, 1); + assertBigMidpointRound(false, 120, 2); + assertBigMidpointRound(false, 120, (1 << 23) - 1); + assertBigMidpointRound(false, 120, (1 << 23) - 2); + + assertBigMidpointRound(false, -120, 1); + assertBigMidpointRound(false, -120, 2); + assertBigMidpointRound(false, -120, (1 << 23) - 1); + assertBigMidpointRound(false, -120, (1 << 23) - 2); + + assertBigMidpointRound(true, 1, 1); + assertBigMidpointRound(true, 1, 2); + assertBigMidpointRound(true, 1, (1 << 23) - 1); + assertBigMidpointRound(true, 1, (1 << 23) - 2); } @Test @@ -63,121 +261,117 @@ public class FloatFormatTest extends AbstractGenericTest { FloatFormat ff = new FloatFormat(4); float f = 4.5f; int intbits = Float.floatToRawIntBits(f); - BigDecimal big = BigDecimal.valueOf(f); + + BigFloat big = ff.getBigFloat(f); BigInteger encoding = ff.getEncoding(big); Assert.assertEquals(intbits, encoding.longValue()); Assert.assertEquals(big, ff.getHostFloat(encoding)); -// f = 8.908155E-39f; -// intbits = Float.floatToRawIntBits(f); -// big = BigDecimal.valueOf(f); -// encoding = ff.getEncoding(big); -// Assert.assertEquals(intbits, encoding.longValue()); -// Assert.assertEquals(big, ff.getHostFloat(encoding)); - f = 3.75f; intbits = Float.floatToRawIntBits(f); - big = BigDecimal.valueOf(f); + big = ff.getBigFloat(f); encoding = ff.getEncoding(big); Assert.assertEquals((intbits) & 0xffffffffL, encoding.longValue()); Assert.assertEquals(big, ff.getHostFloat(encoding)); f = -4.5f; intbits = Float.floatToRawIntBits(f); - big = BigDecimal.valueOf(f); + big = ff.getBigFloat(f); encoding = ff.getEncoding(big); Assert.assertEquals((intbits) & 0xffffffffL, encoding.longValue()); Assert.assertEquals(big, ff.getHostFloat(encoding)); f = Float.POSITIVE_INFINITY; intbits = Float.floatToRawIntBits(f); - encoding = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + encoding = ff.getEncoding(ff.getBigFloat(f)); Assert.assertEquals(intbits, encoding.longValue()); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(encoding)); f = Float.NEGATIVE_INFINITY; intbits = Float.floatToRawIntBits(f); - encoding = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + encoding = ff.getEncoding(ff.getBigFloat(f)); Assert.assertEquals((intbits) & 0xffffffffL, encoding.longValue()); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(encoding)); f = Float.NaN; intbits = Float.floatToRawIntBits(f); - encoding = ff.getEncoding(FloatFormat.BIG_NaN); + encoding = ff.getEncoding(ff.getBigFloat(f)); Assert.assertEquals(intbits, encoding.longValue()); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(encoding)); /// 64-bit encoding ff = new FloatFormat(8); double d = 4.5d; long longbits = Double.doubleToRawLongBits(d); - big = BigDecimal.valueOf(d); + big = ff.getBigFloat(d); encoding = ff.getEncoding(big); Assert.assertEquals(longbits, encoding.longValue()); Assert.assertEquals(big, ff.getHostFloat(encoding)); d = 3.75d; longbits = Double.doubleToRawLongBits(d); - big = BigDecimal.valueOf(d); + big = ff.getBigFloat(d); encoding = ff.getEncoding(big); Assert.assertEquals(longbits, encoding.longValue()); Assert.assertEquals(big, ff.getHostFloat(encoding)); d = -4.5d; longbits = Double.doubleToRawLongBits(d); - big = BigDecimal.valueOf(d); + big = ff.getBigFloat(d); encoding = ff.getEncoding(big); Assert.assertEquals(longbits, encoding.longValue()); Assert.assertEquals(big, ff.getHostFloat(encoding)); d = Double.POSITIVE_INFINITY; longbits = Double.doubleToRawLongBits(d); - encoding = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + + encoding = ff.getBigInfinityEncoding(false); Assert.assertEquals(longbits, encoding.longValue()); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(encoding)); d = Double.NEGATIVE_INFINITY; longbits = Double.doubleToRawLongBits(d); - encoding = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + encoding = ff.getBigInfinityEncoding(true); Assert.assertEquals(longbits, encoding.longValue()); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(encoding)); d = Double.NaN; longbits = Double.doubleToRawLongBits(d); - encoding = ff.getEncoding(FloatFormat.BIG_NaN); + + encoding = ff.getBigNaNEncoding(false); Assert.assertEquals(longbits, encoding.longValue()); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(encoding)); /// 80-bit encoding ff = new FloatFormat(10); - big = BigDecimal.valueOf(4.5); + big = ff.getBigFloat(4.5); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); - big = BigDecimal.valueOf(3.75); + big = ff.getBigFloat(3.75); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); - big = BigDecimal.valueOf(-4.5); + big = ff.getBigFloat(-4.5); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); - big = FloatFormat.BIG_POSITIVE_INFINITY; + big = ff.getBigInfinity(false); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); - big = FloatFormat.BIG_NEGATIVE_INFINITY; + big = ff.getBigInfinity(true); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); - big = FloatFormat.BIG_NaN; + big = ff.getBigNaN(false); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); @@ -185,32 +379,32 @@ public class FloatFormatTest extends AbstractGenericTest { /// 128-bit encoding ff = new FloatFormat(16); - big = BigDecimal.valueOf(4.5); + big = ff.getBigFloat(4.5); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); - big = BigDecimal.valueOf(3.75); + big = ff.getBigFloat(3.75); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); - big = BigDecimal.valueOf(-4.5); + big = ff.getBigFloat(-4.5); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); - big = FloatFormat.BIG_POSITIVE_INFINITY; + big = ff.getBigInfinity(false); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); - big = FloatFormat.BIG_NEGATIVE_INFINITY; + big = ff.getBigInfinity(true); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); - big = FloatFormat.BIG_NaN; + big = ff.getBigNaN(false); encoding = ff.getEncoding(big); // use round trip to verify Assert.assertEquals(big, ff.getHostFloat(encoding)); @@ -305,6 +499,40 @@ public class FloatFormatTest extends AbstractGenericTest { Assert.assertEquals(d, ff.getHostFloat(encoding), 0); } + @Test + public strictfp void testBigFloatFloatFormatRandom() { + Random rand = new Random(1); + FloatFormat floatFormat = FloatFormatFactory.getFloatFormat(4); + + for (int i = 0; i < 1000; ++i) { + float f = rand.nextFloat(); + BigInteger encoding0 = BigInteger.valueOf(Float.floatToRawIntBits(f)); + BigFloat bf1 = floatFormat.getHostFloat(encoding0); + BigFloat bf2 = FloatFormat.toBigFloat(f); + assertEquals(bf1.toString(), bf2.toString()); + BigInteger encoding1 = floatFormat.getEncoding(bf1); + assertEquals(encoding0, encoding1); + } + + } + + @Test + public strictfp void testBigFloatDoubleFormatRandom() { + Random rand = new Random(1); + FloatFormat floatFormat = FloatFormatFactory.getFloatFormat(8); + + for (int i = 0; i < 1000; ++i) { + double f = rand.nextFloat(); + BigInteger encoding0 = BigInteger.valueOf(Double.doubleToLongBits(f)); + BigFloat bf1 = floatFormat.getHostFloat(encoding0); + BigFloat bf2 = FloatFormat.toBigFloat(f); + assertEquals(bf1.toString(), bf2.toString()); + BigInteger encoding1 = floatFormat.getEncoding(bf1); + assertEquals(encoding0, encoding1); + } + + } + @Test public void testOpEqualLongLong() { FloatFormat ff = new FloatFormat(8); @@ -324,23 +552,19 @@ public class FloatFormatTest extends AbstractGenericTest { @Test public void testOpEqualBigIntegerBigInteger() { FloatFormat ff = new FloatFormat(8); - BigDecimal a = BigDecimal.valueOf(1.234d); - BigDecimal b = BigDecimal.valueOf(-1.234d); + BigFloat a = ff.getBigFloat(1.234d); + BigFloat b = ff.getBigFloat(-1.234d); Assert.assertEquals(BigInteger.ONE, ff.opEqual(ff.getEncoding(a), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ONE, ff.opEqual(ff.getEncoding(b), ff.getEncoding(b))); Assert.assertEquals(BigInteger.ZERO, ff.opEqual(ff.getEncoding(b), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ONE, - ff.opEqual(ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); + ff.opEqual(ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(false))); Assert.assertEquals(BigInteger.ZERO, - ff.opEqual(ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); + ff.opEqual(ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(true))); Assert.assertEquals(BigInteger.ONE, - ff.opEqual(ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); + ff.opEqual(ff.getBigInfinityEncoding(true), ff.getBigInfinityEncoding(true))); Assert.assertEquals(BigInteger.ZERO, - ff.opEqual(ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NaN))); + ff.opEqual(ff.getBigInfinityEncoding(false), ff.getBigNaNEncoding(false))); } @Test @@ -362,23 +586,20 @@ public class FloatFormatTest extends AbstractGenericTest { @Test public void testOpNotEqualBigIntegerBigInteger() { FloatFormat ff = new FloatFormat(8); - BigDecimal a = BigDecimal.valueOf(1.234d); - BigDecimal b = BigDecimal.valueOf(-1.234d); + + BigFloat a = ff.getBigFloat(1.234d); + BigFloat b = ff.getBigFloat(-1.234d); Assert.assertEquals(BigInteger.ZERO, ff.opNotEqual(ff.getEncoding(a), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ZERO, ff.opNotEqual(ff.getEncoding(b), ff.getEncoding(b))); Assert.assertEquals(BigInteger.ONE, ff.opNotEqual(ff.getEncoding(b), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ZERO, - ff.opNotEqual(ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); + ff.opNotEqual(ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(false))); Assert.assertEquals(BigInteger.ONE, - ff.opNotEqual(ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); + ff.opNotEqual(ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(true))); Assert.assertEquals(BigInteger.ZERO, - ff.opNotEqual(ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); + ff.opNotEqual(ff.getBigInfinityEncoding(true), ff.getBigInfinityEncoding(true))); Assert.assertEquals(BigInteger.ONE, - ff.opNotEqual(ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NaN))); + ff.opNotEqual(ff.getBigInfinityEncoding(false), ff.getBigNaNEncoding(false))); } @Test @@ -411,34 +632,32 @@ public class FloatFormatTest extends AbstractGenericTest { @Test public void testOpLessBigIntegerBigInteger() { FloatFormat ff = new FloatFormat(8); - BigDecimal a = BigDecimal.valueOf(1.234d); - BigDecimal b = BigDecimal.valueOf(-1.234d); + BigFloat a = ff.getBigFloat(1.234d); + BigFloat b = ff.getBigFloat(-1.234d); Assert.assertEquals(BigInteger.ZERO, ff.opLess(ff.getEncoding(a), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ZERO, ff.opLess(ff.getEncoding(b), ff.getEncoding(b))); Assert.assertEquals(BigInteger.ZERO, ff.opLess(ff.getEncoding(a), ff.getEncoding(b))); Assert.assertEquals(BigInteger.ZERO, - ff.opLess(ff.getEncoding(BigDecimal.ZERO), ff.getEncoding(b))); + ff.opLess(ff.getBigZeroEncoding(false), ff.getEncoding(b))); Assert.assertEquals(BigInteger.ONE, - ff.opLess(ff.getEncoding(BigDecimal.ZERO), ff.getEncoding(a))); + ff.opLess(ff.getBigZeroEncoding(false), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ONE, ff.opLess(ff.getEncoding(b), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ZERO, - ff.opLess(ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), ff.getEncoding(a))); + ff.opLess(ff.getBigInfinityEncoding(false), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ONE, - ff.opLess(ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), ff.getEncoding(a))); + ff.opLess(ff.getBigInfinityEncoding(true), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ONE, - ff.opLess(ff.getEncoding(a), ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); + ff.opLess(ff.getEncoding(a), ff.getBigInfinityEncoding(false))); Assert.assertEquals(BigInteger.ZERO, - ff.opLess(ff.getEncoding(a), ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); + ff.opLess(ff.getEncoding(a), ff.getBigInfinityEncoding(true))); Assert.assertEquals(BigInteger.ZERO, - ff.opLess(ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); + ff.opLess(ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(false))); Assert.assertEquals(BigInteger.ONE, - ff.opLess(ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); + ff.opLess(ff.getBigInfinityEncoding(true), ff.getBigInfinityEncoding(false))); } @Test @@ -472,35 +691,33 @@ public class FloatFormatTest extends AbstractGenericTest { @Test public void testOpLessEqualBigIntegerBigInteger() { FloatFormat ff = new FloatFormat(8); - BigDecimal a = BigDecimal.valueOf(1.234d); - BigDecimal b = BigDecimal.valueOf(-1.234d); + BigFloat a = ff.getBigFloat(1.234d); + BigFloat b = ff.getBigFloat(-1.234d); Assert.assertEquals(BigInteger.ONE, ff.opLessEqual(ff.getEncoding(a), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ONE, ff.opLessEqual(ff.getEncoding(b), ff.getEncoding(b))); Assert.assertEquals(BigInteger.ZERO, ff.opLessEqual(ff.getEncoding(a), ff.getEncoding(b))); Assert.assertEquals(BigInteger.ZERO, - ff.opLessEqual(ff.getEncoding(BigDecimal.ZERO), ff.getEncoding(b))); + ff.opLessEqual(ff.getBigZeroEncoding(false), ff.getEncoding(b))); Assert.assertEquals(BigInteger.ONE, - ff.opLessEqual(ff.getEncoding(BigDecimal.ZERO), ff.getEncoding(a))); + ff.opLessEqual(ff.getBigZeroEncoding(false), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ONE, ff.opLessEqual(ff.getEncoding(b), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ZERO, - ff.opLessEqual(ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), ff.getEncoding(a))); + ff.opLessEqual(ff.getBigInfinityEncoding(false), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ONE, - ff.opLessEqual(ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), ff.getEncoding(a))); + ff.opLessEqual(ff.getBigInfinityEncoding(true), ff.getEncoding(a))); Assert.assertEquals(BigInteger.ONE, - ff.opLessEqual(ff.getEncoding(a), ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); + ff.opLessEqual(ff.getEncoding(a), ff.getBigInfinityEncoding(false))); Assert.assertEquals(BigInteger.ZERO, - ff.opLessEqual(ff.getEncoding(a), ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); + ff.opLessEqual(ff.getEncoding(a), ff.getBigInfinityEncoding(true))); Assert.assertEquals(BigInteger.ONE, - ff.opLessEqual(ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); + ff.opLessEqual(ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(false))); Assert.assertEquals(BigInteger.ONE, - ff.opLessEqual(ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); + ff.opLessEqual(ff.getBigInfinityEncoding(true), ff.getBigInfinityEncoding(false))); } @Test @@ -514,9 +731,9 @@ public class FloatFormatTest extends AbstractGenericTest { @Test public void testOpNanBigInteger() { FloatFormat ff = new FloatFormat(8); - Assert.assertEquals(BigInteger.ONE, ff.opNan(ff.getEncoding(FloatFormat.BIG_NaN))); - Assert.assertEquals(BigInteger.ZERO, ff.opNan(ff.getEncoding(BigDecimal.ZERO))); - Assert.assertEquals(BigInteger.ZERO, ff.opNan(ff.getEncoding(BigDecimal.valueOf(1.234d)))); + Assert.assertEquals(BigInteger.ONE, ff.opNan(ff.getBigNaNEncoding(false))); + Assert.assertEquals(BigInteger.ZERO, ff.opNan(ff.getBigZeroEncoding(false))); + Assert.assertEquals(BigInteger.ZERO, ff.opNan(ff.getEncoding(ff.getBigFloat(1.234d)))); } @Test @@ -558,35 +775,35 @@ public class FloatFormatTest extends AbstractGenericTest { public void testOpAddBigIntegerBigInteger() { FloatFormat ff = new FloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(1.234d)); - BigInteger b = ff.getEncoding(BigDecimal.valueOf(1.123d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(1.234d)); + BigInteger b = ff.getEncoding(ff.getBigFloat(1.123d)); BigInteger result = ff.opAdd(a, b);// 1.234 + 1.123 - Assert.assertEquals(BigDecimal.valueOf(2.357), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.357), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-1.123d)); + a = ff.getEncoding(ff.getBigFloat(-1.123d)); result = ff.opAdd(a, b);// -1.123 + 1.123 - Assert.assertEquals(BigDecimal.ZERO, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigZero(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = ff.opAdd(a, b);// +INFINITY + 1.123 - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = ff.opAdd(a, b);// -INFINITY + 1.123 - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + b = ff.getBigInfinityEncoding(true); result = ff.opAdd(a, b);// -INFINITY + -INFINITY - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + b = ff.getBigInfinityEncoding(false); result = ff.opAdd(a, b);// -INFINITY + +INFINITY - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); - b = ff.getEncoding(BigDecimal.valueOf(1.123d)); + a = ff.getBigNaNEncoding(false); + b = ff.getEncoding(ff.getBigFloat(1.123d)); result = ff.opAdd(a, b);// NaN + 1.123 - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } @Test @@ -628,35 +845,35 @@ public class FloatFormatTest extends AbstractGenericTest { public void testOpSubBigIntegerBigInteger() { FloatFormat ff = new FloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(1.5d)); - BigInteger b = ff.getEncoding(BigDecimal.valueOf(1.25d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(1.5d)); + BigInteger b = ff.getEncoding(ff.getBigFloat(1.25d)); BigInteger result = ff.opSub(a, b);// 1.5 - 1.25 - Assert.assertEquals(BigDecimal.valueOf(0.25d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(0.25d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-1.25d)); + a = ff.getEncoding(ff.getBigFloat(-1.25d)); result = ff.opSub(a, b);// -1.25 - 1.25 - Assert.assertEquals(BigDecimal.valueOf(-2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.5d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = ff.opSub(a, b);// +INFINITY - 1.25 - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = ff.opSub(a, b);// -INFINITY - 1.25 - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + b = ff.getBigInfinityEncoding(true); result = ff.opSub(a, b);// -INFINITY - -INFINITY - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + b = ff.getBigInfinityEncoding(false); result = ff.opSub(a, b);// -INFINITY - +INFINITY - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); - b = ff.getEncoding(BigDecimal.valueOf(1.25d)); + a = ff.getBigNaNEncoding(false); + b = ff.getEncoding(ff.getBigFloat(1.25d)); result = ff.opSub(a, b);// NaN - 1.25 - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } @Test @@ -685,22 +902,22 @@ public class FloatFormatTest extends AbstractGenericTest { public void testOpDivBigIntegerBigInteger() { FloatFormat ff = new FloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(3.75d)); - BigInteger b = ff.getEncoding(BigDecimal.valueOf(1.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(3.75d)); + BigInteger b = ff.getEncoding(ff.getBigFloat(1.5d)); BigInteger result = ff.opDiv(a, b); - Assert.assertEquals(BigDecimal.valueOf(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); - b = ff.getEncoding(BigDecimal.ZERO); + b = ff.getBigZeroEncoding(false); result = ff.opDiv(a, b); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-3.75d)); + a = ff.getEncoding(ff.getBigFloat(-3.75d)); result = ff.opDiv(a, b); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_NaN); + b = ff.getBigNaNEncoding(false); result = ff.opDiv(a, b); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } @Test @@ -729,22 +946,22 @@ public class FloatFormatTest extends AbstractGenericTest { public void testOpMultBigIntegerBigInteger() { FloatFormat ff = new FloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); - BigInteger b = ff.getEncoding(BigDecimal.valueOf(1.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); + BigInteger b = ff.getEncoding(ff.getBigFloat(1.5d)); BigInteger result = ff.opMult(a, b); - Assert.assertEquals(BigDecimal.valueOf(3.75d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.75d), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + b = ff.getBigInfinityEncoding(false); result = ff.opMult(a, b); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = ff.opMult(a, b); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_NaN); + b = ff.getBigNaNEncoding(false); result = ff.opMult(a, b); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } @Test @@ -776,25 +993,25 @@ public class FloatFormatTest extends AbstractGenericTest { public void testOpNegBigInteger() { FloatFormat ff = new FloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = ff.opNeg(a); - Assert.assertEquals(BigDecimal.valueOf(-2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.5d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = ff.opNeg(a); - Assert.assertEquals(BigDecimal.valueOf(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = ff.opNeg(a); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = ff.opNeg(a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = ff.opNeg(a); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } @Test @@ -826,25 +1043,25 @@ public class FloatFormatTest extends AbstractGenericTest { public void testOpAbsBigInteger() { FloatFormat ff = new FloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = ff.opAbs(a); - Assert.assertEquals(BigDecimal.valueOf(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = ff.opAbs(a); - Assert.assertEquals(BigDecimal.valueOf(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = ff.opAbs(a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = ff.opAbs(a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = ff.opAbs(a); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } @Test @@ -859,11 +1076,11 @@ public class FloatFormatTest extends AbstractGenericTest { @Test public void testOpSqrtBigInteger() { FloatFormat ff = new FloatFormat(8); - BigDecimal big = BigDecimal.valueOf(2.0); + BigFloat big = ff.getBigFloat(2.0); BigInteger encoding = ff.getEncoding(big); encoding = ff.opSqrt(encoding); - BigDecimal result = ff.getHostFloat(encoding); - Assert.assertEquals("1.414213562373095", result.toString()); + BigFloat result = ff.getHostFloat(encoding); + Assert.assertEquals("1.414213562373095", ff.round(result).toString()); } @Test @@ -891,16 +1108,46 @@ public class FloatFormatTest extends AbstractGenericTest { BigInteger result = ff.opInt2Float(BigInteger.valueOf(2), 4, true); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(BigDecimal.valueOf(2.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); result = ff.opInt2Float(BigInteger.valueOf(-2), 4, true); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(BigDecimal.valueOf(-2.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); result = ff.opInt2Float(BigInteger.ZERO, 4, true); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(BigDecimal.ZERO, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigZero(false), ff.getHostFloat(result)); + } + + @Test + public void testBigFloatToDoubleEncoding() { + FloatFormat ff8 = new FloatFormat(8); + int i = 0; + for (double d : BigFloatTest.testDoubleList) { + long e = Double.doubleToRawLongBits(d); + BigFloat bd = FloatFormat.toBigFloat(d); + BigInteger be = ff8.getEncoding(bd); + assertEquals("case #" + Integer.toString(i), e, be.longValue()); + ++i; + } + } + + @Test + public void testBigFloatToFloatEncoding() { + FloatFormat ff8 = new FloatFormat(4); + int i = 0; + for (float f : BigFloatTest.testFloatList) { + int e = Float.floatToRawIntBits(f); + BigFloat bf = FloatFormat.toBigFloat(f); + if (Float.isNaN(f)) { + assertTrue("case #" + Integer.toString(i), bf.isNaN()); + } + else { + BigInteger be = ff8.getEncoding(bf); + assertEquals("case #" + Integer.toString(i), e, be.intValue()); + } + ++i; + } } @Test @@ -935,25 +1182,25 @@ public class FloatFormatTest extends AbstractGenericTest { FloatFormat ff8 = new FloatFormat(8); FloatFormat ff4 = new FloatFormat(4); - BigInteger a = ff4.getEncoding(BigDecimal.valueOf(1.75d)); + BigInteger a = ff4.getEncoding(ff4.getBigFloat(1.75d)); BigInteger result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(BigDecimal.valueOf(1.75d), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigFloat(1.75d), ff8.getHostFloat(result)); - a = ff4.getEncoding(BigDecimal.valueOf(-1.75d)); + a = ff4.getEncoding(ff4.getBigFloat(-1.75d)); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(BigDecimal.valueOf(-1.75d), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigFloat(-1.75d), ff8.getHostFloat(result)); - a = ff4.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff4.getEncoding(ff4.getBigInfinity(false)); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigInfinity(false), ff8.getHostFloat(result)); - a = ff4.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff4.getEncoding(ff4.getBigInfinity(true)); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigInfinity(true), ff8.getHostFloat(result)); - a = ff4.getEncoding(FloatFormat.BIG_NaN); + a = ff4.getEncoding(ff4.getBigNaN(false)); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(FloatFormat.BIG_NaN, ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigNaN(false), ff8.getHostFloat(result)); } @Test @@ -986,24 +1233,24 @@ public class FloatFormatTest extends AbstractGenericTest { public void testOpTruncBigIntegerInt() { FloatFormat ff = new FloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = ff.opTrunc(a, 8); Assert.assertEquals(BigInteger.valueOf(2), result); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = ff.opTrunc(a, 8); Assert.assertEquals(BigInteger.valueOf(-2), result); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = ff.opTrunc(a, 8); Assert.assertEquals(BigInteger.valueOf(Long.MAX_VALUE), result); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = ff.opTrunc(a, 8); Assert.assertEquals(BigInteger.valueOf(Long.MIN_VALUE), result); // TODO: What should the correct result be? - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = ff.opTrunc(a, 8); Assert.assertEquals(BigInteger.ZERO, result); } @@ -1037,26 +1284,25 @@ public class FloatFormatTest extends AbstractGenericTest { public void testOpCeilBigInteger() { FloatFormat ff = new FloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = ff.opCeil(a); - Assert.assertEquals(BigDecimal.valueOf(3.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = ff.opCeil(a); - Assert.assertEquals(BigDecimal.valueOf(-2.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = ff.opCeil(a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = ff.opCeil(a); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = ff.opCeil(a); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } @Test @@ -1092,31 +1338,29 @@ public class FloatFormatTest extends AbstractGenericTest { public void testOpFloorBigInteger() { FloatFormat ff = new FloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = ff.opFloor(a); - Assert.assertEquals(BigDecimal.valueOf(2.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.0d)); + a = ff.getEncoding(ff.getBigFloat(-2.0d)); result = ff.opFloor(a); - Assert.assertEquals(BigDecimal.valueOf(-2.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = ff.opFloor(a); - Assert.assertEquals(BigDecimal.valueOf(-3.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-3.0d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = ff.opFloor(a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = ff.opFloor(a); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = ff.opFloor(a); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } @Test @@ -1164,44 +1408,41 @@ public class FloatFormatTest extends AbstractGenericTest { public void testOpRoundBigInteger() { FloatFormat ff = new FloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = ff.opRound(a); - Assert.assertEquals(BigDecimal.valueOf(3.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(2.25d)); + a = ff.getEncoding(ff.getBigFloat(2.25d)); result = ff.opRound(a); - Assert.assertEquals(BigDecimal.valueOf(2.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(2.75d)); + a = ff.getEncoding(ff.getBigFloat(2.75d)); result = ff.opRound(a); - Assert.assertEquals(BigDecimal.valueOf(3.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = ff.opRound(a); - Assert.assertEquals(BigDecimal.valueOf(-2.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.25d)); + a = ff.getEncoding(ff.getBigFloat(-2.25d)); result = ff.opRound(a); - Assert.assertEquals(BigDecimal.valueOf(-2.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.75d)); + a = ff.getEncoding(ff.getBigFloat(-2.75d)); result = ff.opRound(a); - Assert.assertEquals(BigDecimal.valueOf(-3.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-3.0d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = ff.opRound(a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = ff.opRound(a); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = ff.opRound(a); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAbsTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAbsTest.java index da6f63215b..bf1a407cb2 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAbsTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAbsTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -65,25 +64,25 @@ public class OpBehaviorFloatAbsTest extends AbstractOpBehaviorTest { FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAddTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAddTest.java index 711348892b..4a7f4267c1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAddTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAddTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -75,35 +74,35 @@ public class OpBehaviorFloatAddTest extends AbstractOpBehaviorTest { FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(1.234d)); - BigInteger b = ff.getEncoding(BigDecimal.valueOf(1.123d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(1.234d)); + BigInteger b = ff.getEncoding(ff.getBigFloat(1.123d)); BigInteger result = op.evaluateBinary(8, 8, a, b);// 1.234 + 1.123 - Assert.assertEquals(BigDecimal.valueOf(2.357), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.357), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-1.123d)); + a = ff.getEncoding(ff.getBigFloat(-1.123d)); result = op.evaluateBinary(8, 8, a, b);// -1.123 + 1.123 - Assert.assertEquals(BigDecimal.ZERO, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigZero(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getEncoding(ff.getBigInfinity(false)); result = op.evaluateBinary(8, 8, a, b);// +INFINITY + 1.123 - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = op.evaluateBinary(8, 8, a, b);// -INFINITY + 1.123 - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + b = ff.getBigInfinityEncoding(true); result = op.evaluateBinary(8, 8, a, b);// -INFINITY + -INFINITY - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + b = ff.getEncoding(ff.getBigInfinity(false)); result = op.evaluateBinary(8, 8, a, b);// -INFINITY + +INFINITY - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); - b = ff.getEncoding(BigDecimal.valueOf(1.123d)); + a = ff.getBigNaNEncoding(false); + b = ff.getEncoding(ff.getBigFloat(1.123d)); result = op.evaluateBinary(8, 8, a, b);// NaN + 1.123 - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatCeilTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatCeilTest.java index 6f95d93fa6..119c360acc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatCeilTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatCeilTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -65,26 +64,25 @@ public class OpBehaviorFloatCeilTest extends AbstractOpBehaviorTest { FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(3.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(-2.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatDivTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatDivTest.java index 2b4c801a31..76d484ee4e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatDivTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatDivTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -62,22 +61,22 @@ public class OpBehaviorFloatDivTest extends AbstractOpBehaviorTest { FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(3.75d)); - BigInteger b = ff.getEncoding(BigDecimal.valueOf(1.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(3.75d)); + BigInteger b = ff.getEncoding(ff.getBigFloat(1.5d)); BigInteger result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(BigDecimal.valueOf(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); - b = ff.getEncoding(BigDecimal.ZERO); + b = ff.getBigZeroEncoding(false); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-3.75d)); + a = ff.getEncoding(ff.getBigFloat(-3.75d)); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_NaN); + b = ff.getBigNaNEncoding(false); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatEqualTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatEqualTest.java index 8db089c1fd..040d867b35 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatEqualTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatEqualTest.java @@ -15,14 +15,12 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; import org.junit.Test; -import ghidra.pcode.floatformat.FloatFormat; -import ghidra.pcode.floatformat.FloatFormatFactory; +import ghidra.pcode.floatformat.*; public class OpBehaviorFloatEqualTest extends AbstractOpBehaviorTest { @@ -30,63 +28,53 @@ public class OpBehaviorFloatEqualTest extends AbstractOpBehaviorTest { super(); } -@Test - public void testEvaluateBinaryLong() { + @Test + public void testEvaluateBinaryLong() { OpBehaviorFloatEqual op = new OpBehaviorFloatEqual(); FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(1.234))); - Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(-1.234))); - Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(1.234))); - Assert.assertEquals( - 1, - op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), - ff.getEncoding(Double.POSITIVE_INFINITY))); - Assert.assertEquals( - 0, - op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), - ff.getEncoding(Double.NEGATIVE_INFINITY))); - Assert.assertEquals( - 1, - op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), - ff.getEncoding(Double.NEGATIVE_INFINITY))); - Assert.assertEquals( - 0, - op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), - ff.getEncoding(Double.NaN))); + Assert.assertEquals(1, + op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(1.234))); + Assert.assertEquals(1, + op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(-1.234))); + Assert.assertEquals(0, + op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(1.234))); + Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), + ff.getEncoding(Double.POSITIVE_INFINITY))); + Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), + ff.getEncoding(Double.NEGATIVE_INFINITY))); + Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), + ff.getEncoding(Double.NEGATIVE_INFINITY))); + Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), + ff.getEncoding(Double.NaN))); } -@Test - public void testEvaluateBinaryBigInteger() { + @Test + public void testEvaluateBinaryBigInteger() { OpBehaviorFloatEqual op = new OpBehaviorFloatEqual(); FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigDecimal a = BigDecimal.valueOf(1.234d); - BigDecimal b = BigDecimal.valueOf(-1.234d); - Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(a))); - Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(b))); - Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(a))); - Assert.assertEquals( - BigInteger.ONE, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); - Assert.assertEquals( - BigInteger.ZERO, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); - Assert.assertEquals( - BigInteger.ONE, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); - Assert.assertEquals( - BigInteger.ZERO, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NaN))); + BigFloat a = ff.getBigFloat(1.234d); + BigFloat b = ff.getBigFloat(-1.234d); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(b))); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, + ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(false))); + Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(8, 8, + ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(true))); + Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(true), + ff.getBigInfinityEncoding(true))); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(false), ff.getBigNaNEncoding(false))); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloat2FloatTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloat2FloatTest.java index b376b43355..b67798e0f3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloat2FloatTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloat2FloatTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -67,25 +66,25 @@ public class OpBehaviorFloatFloat2FloatTest extends AbstractOpBehaviorTest { FloatFormat ff8 = FloatFormatFactory.getFloatFormat(8); FloatFormat ff4 = FloatFormatFactory.getFloatFormat(4); - BigInteger a = ff4.getEncoding(BigDecimal.valueOf(1.75d)); + BigInteger a = ff4.getEncoding(ff4.getBigFloat(1.75d)); BigInteger result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(BigDecimal.valueOf(1.75d), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigFloat(1.75d), ff8.getHostFloat(result)); - a = ff4.getEncoding(BigDecimal.valueOf(-1.75d)); + a = ff4.getEncoding(ff4.getBigFloat(-1.75d)); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(BigDecimal.valueOf(-1.75d), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigFloat(-1.75d), ff8.getHostFloat(result)); - a = ff4.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff4.getEncoding(ff4.getBigInfinity(false)); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigInfinity(false), ff8.getHostFloat(result)); - a = ff4.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff4.getEncoding(ff4.getBigInfinity(true)); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigInfinity(true), ff8.getHostFloat(result)); - a = ff4.getEncoding(FloatFormat.BIG_NaN); + a = ff4.getEncoding(ff4.getBigNaN(false)); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(FloatFormat.BIG_NaN, ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigNaN(false), ff8.getHostFloat(result)); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloorTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloorTest.java index f9e22bc4e0..8841e3fd45 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloorTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloorTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -69,31 +68,29 @@ public class OpBehaviorFloatFloorTest extends AbstractOpBehaviorTest { FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(2.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.0d)); + a = ff.getEncoding(ff.getBigFloat(-2.0d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(-2.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(-3.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-3.0d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatInt2FloatTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatInt2FloatTest.java index fc02f3fec3..bb93e7bcca 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatInt2FloatTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatInt2FloatTest.java @@ -15,9 +15,8 @@ */ package ghidra.pcode.opbehavior; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -68,22 +67,20 @@ public class OpBehaviorFloatInt2FloatTest extends AbstractOpBehaviorTest { BigInteger result = op.evaluateUnary(4, 4, BigInteger.valueOf(2)); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(BigDecimal.valueOf(2.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); result = op.evaluateUnary(4, 4, BigInteger.valueOf(-2)); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(BigDecimal.valueOf(-2.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); result = op.evaluateUnary(4, 4, BigInteger.ZERO); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(BigDecimal.ZERO, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigZero(false), ff.getHostFloat(result)); BigInteger NEG_ONE = Utils.bytesToBigInteger( new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 4, false, false); result = op.evaluateUnary(4, 4, NEG_ONE); - Assert.assertEquals(BigDecimal.valueOf(-1.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-1.0d), ff.getHostFloat(result)); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatLessEqualTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatLessEqualTest.java index 4bfa84f826..2c6de5cf57 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatLessEqualTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatLessEqualTest.java @@ -15,14 +15,12 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; import org.junit.Test; -import ghidra.pcode.floatformat.FloatFormat; -import ghidra.pcode.floatformat.FloatFormatFactory; +import ghidra.pcode.floatformat.*; public class OpBehaviorFloatLessEqualTest extends AbstractOpBehaviorTest { @@ -30,92 +28,80 @@ public class OpBehaviorFloatLessEqualTest extends AbstractOpBehaviorTest { super(); } -@Test - public void testEvaluateBinaryLong() { + @Test + public void testEvaluateBinaryLong() { OpBehaviorFloatLessEqual op = new OpBehaviorFloatLessEqual(); FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(1.234))); - Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(-1.234))); + Assert.assertEquals(1, + op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(1.234))); + Assert.assertEquals(1, + op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(-1.234))); - Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(-1.234))); + Assert.assertEquals(0, + op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(-1.234))); Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(0), ff.getEncoding(-1.234))); Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(0), ff.getEncoding(1.234))); - Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(1.234))); + Assert.assertEquals(1, + op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(1.234))); - Assert.assertEquals( - 0, - op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), ff.getEncoding(1.234))); - Assert.assertEquals( - 1, - op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), ff.getEncoding(1.234))); - Assert.assertEquals( - 1, - op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(Double.POSITIVE_INFINITY))); - Assert.assertEquals( - 0, - op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(Double.NEGATIVE_INFINITY))); + Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), + ff.getEncoding(1.234))); + Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), + ff.getEncoding(1.234))); + Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(1.234), + ff.getEncoding(Double.POSITIVE_INFINITY))); + Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(1.234), + ff.getEncoding(Double.NEGATIVE_INFINITY))); - Assert.assertEquals( - 1, - op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), - ff.getEncoding(Double.POSITIVE_INFINITY))); - Assert.assertEquals( - 1, - op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), - ff.getEncoding(Double.POSITIVE_INFINITY))); + Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), + ff.getEncoding(Double.POSITIVE_INFINITY))); + Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), + ff.getEncoding(Double.POSITIVE_INFINITY))); } -@Test - public void testEvaluateBinaryBigInteger() { + @Test + public void testEvaluateBinaryBigInteger() { OpBehaviorFloatLessEqual op = new OpBehaviorFloatLessEqual(); FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigDecimal a = BigDecimal.valueOf(1.234d); - BigDecimal b = BigDecimal.valueOf(-1.234d); - - Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(a))); - Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(b))); - - Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(b))); - Assert.assertEquals(BigInteger.ZERO, - op.evaluateBinary(8, 8, ff.getEncoding(BigDecimal.ZERO), ff.getEncoding(b))); + BigFloat a = ff.getBigFloat(1.234d); + BigFloat b = ff.getBigFloat(-1.234d); Assert.assertEquals(BigInteger.ONE, - op.evaluateBinary(8, 8, ff.getEncoding(BigDecimal.ZERO), ff.getEncoding(a))); - Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(a))); + op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(b))); - Assert.assertEquals( - BigInteger.ZERO, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(a))); - Assert.assertEquals( - BigInteger.ONE, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), - ff.getEncoding(a))); - Assert.assertEquals( - BigInteger.ONE, - op.evaluateBinary(8, 8, ff.getEncoding(a), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); - Assert.assertEquals( - BigInteger.ZERO, - op.evaluateBinary(8, 8, ff.getEncoding(a), - ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(b))); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(8, 8, ff.getBigZeroEncoding(false), ff.getEncoding(b))); - Assert.assertEquals( - BigInteger.ONE, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); - Assert.assertEquals( - BigInteger.ONE, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(8, 8, ff.getBigZeroEncoding(false), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(a))); + + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(false), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(true), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getBigInfinityEncoding(false))); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getBigInfinityEncoding(true))); + + Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, + ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(false))); + Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(true), + ff.getBigInfinityEncoding(false))); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatLessTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatLessTest.java index 625b120d45..a8651ba59e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatLessTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatLessTest.java @@ -15,14 +15,12 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; import org.junit.Test; -import ghidra.pcode.floatformat.FloatFormat; -import ghidra.pcode.floatformat.FloatFormatFactory; +import ghidra.pcode.floatformat.*; public class OpBehaviorFloatLessTest extends AbstractOpBehaviorTest { @@ -30,89 +28,77 @@ public class OpBehaviorFloatLessTest extends AbstractOpBehaviorTest { super(); } -@Test - public void testEvaluateBinaryLong() { + @Test + public void testEvaluateBinaryLong() { OpBehaviorFloatLess op = new OpBehaviorFloatLess(); FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(1.234))); - Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(-1.234))); - Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(-1.234))); + Assert.assertEquals(0, + op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(1.234))); + Assert.assertEquals(0, + op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(-1.234))); + Assert.assertEquals(0, + op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(-1.234))); Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(0), ff.getEncoding(-1.234))); Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(0), ff.getEncoding(1.234))); - Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(1.234))); + Assert.assertEquals(1, + op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(1.234))); - Assert.assertEquals( - 0, - op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), ff.getEncoding(1.234))); - Assert.assertEquals( - 1, - op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), ff.getEncoding(1.234))); - Assert.assertEquals( - 1, - op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(Double.POSITIVE_INFINITY))); - Assert.assertEquals( - 0, - op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(Double.NEGATIVE_INFINITY))); + Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), + ff.getEncoding(1.234))); + Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), + ff.getEncoding(1.234))); + Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(1.234), + ff.getEncoding(Double.POSITIVE_INFINITY))); + Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(1.234), + ff.getEncoding(Double.NEGATIVE_INFINITY))); - Assert.assertEquals( - 0, - op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), - ff.getEncoding(Double.POSITIVE_INFINITY))); - Assert.assertEquals( - 1, - op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), - ff.getEncoding(Double.POSITIVE_INFINITY))); + Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY), + ff.getEncoding(Double.POSITIVE_INFINITY))); + Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), + ff.getEncoding(Double.POSITIVE_INFINITY))); } -@Test - public void testEvaluateBinaryBigInteger() { + @Test + public void testEvaluateBinaryBigInteger() { OpBehaviorFloatLess op = new OpBehaviorFloatLess(); FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigDecimal a = BigDecimal.valueOf(1.234d); - BigDecimal b = BigDecimal.valueOf(-1.234d); + BigFloat a = ff.getBigFloat(1.234d); + BigFloat b = ff.getBigFloat(-1.234d); - Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(a))); - Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(b))); - Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(b))); Assert.assertEquals(BigInteger.ZERO, - op.evaluateBinary(8, 8, ff.getEncoding(BigDecimal.ZERO), ff.getEncoding(b))); + op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(b))); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(b))); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(8, 8, ff.getBigZeroEncoding(false), ff.getEncoding(b))); Assert.assertEquals(BigInteger.ONE, - op.evaluateBinary(8, 8, ff.getEncoding(BigDecimal.ZERO), ff.getEncoding(a))); - Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(a))); + op.evaluateBinary(8, 8, ff.getBigZeroEncoding(false), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(a))); - Assert.assertEquals( - BigInteger.ZERO, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(a))); - Assert.assertEquals( - BigInteger.ONE, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), - ff.getEncoding(a))); - Assert.assertEquals( - BigInteger.ONE, - op.evaluateBinary(8, 8, ff.getEncoding(a), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); - Assert.assertEquals( - BigInteger.ZERO, - op.evaluateBinary(8, 8, ff.getEncoding(a), - ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(false), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(true), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getBigInfinityEncoding(false))); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getBigInfinityEncoding(true))); - Assert.assertEquals( - BigInteger.ZERO, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); - Assert.assertEquals( - BigInteger.ONE, - op.evaluateBinary(8, 8, ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); + Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(8, 8, + ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(false))); + Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(true), + ff.getBigInfinityEncoding(false))); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatMultTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatMultTest.java index e3ac578755..fb83fa3f8a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatMultTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatMultTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -62,22 +61,22 @@ public class OpBehaviorFloatMultTest extends AbstractOpBehaviorTest { FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); - BigInteger b = ff.getEncoding(BigDecimal.valueOf(1.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); + BigInteger b = ff.getEncoding(ff.getBigFloat(1.5d)); BigInteger result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(BigDecimal.valueOf(3.75d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.75d), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + b = ff.getBigInfinityEncoding(false); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_NaN); + b = ff.getBigNaNEncoding(false); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNanTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNanTest.java index ca3822a394..1d38903d63 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNanTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNanTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -30,8 +29,8 @@ public class OpBehaviorFloatNanTest extends AbstractOpBehaviorTest { super(); } -@Test - public void testEvaluateBinaryLong() { + @Test + public void testEvaluateBinaryLong() { OpBehaviorFloatNan op = new OpBehaviorFloatNan(); @@ -42,17 +41,17 @@ public class OpBehaviorFloatNanTest extends AbstractOpBehaviorTest { Assert.assertEquals(0, op.evaluateUnary(1, 8, ff.getEncoding(1.234))); } -@Test - public void testEvaluateBinaryBigInteger() { + @Test + public void testEvaluateBinaryBigInteger() { OpBehaviorFloatNan op = new OpBehaviorFloatNan(); FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - Assert.assertEquals(BigInteger.ONE, op.evaluateUnary(1, 8, ff.getEncoding(FloatFormat.BIG_NaN))); - Assert.assertEquals(BigInteger.ZERO, op.evaluateUnary(1, 8, ff.getEncoding(BigDecimal.ZERO))); + Assert.assertEquals(BigInteger.ONE, op.evaluateUnary(1, 8, ff.getBigNaNEncoding(false))); + Assert.assertEquals(BigInteger.ZERO, op.evaluateUnary(1, 8, ff.getBigZeroEncoding(false))); Assert.assertEquals(BigInteger.ZERO, - op.evaluateUnary(1, 8, ff.getEncoding(BigDecimal.valueOf(1.234d)))); + op.evaluateUnary(1, 8, ff.getEncoding(ff.getBigFloat(1.234d)))); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNegTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNegTest.java index 8c01e2ad8f..257507e6eb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNegTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNegTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -65,25 +64,25 @@ public class OpBehaviorFloatNegTest extends AbstractOpBehaviorTest { FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(-2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.5d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNotEqualTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNotEqualTest.java index 184ec8a083..acd9626214 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNotEqualTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNotEqualTest.java @@ -15,14 +15,12 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; import org.junit.Test; -import ghidra.pcode.floatformat.FloatFormat; -import ghidra.pcode.floatformat.FloatFormatFactory; +import ghidra.pcode.floatformat.*; public class OpBehaviorFloatNotEqualTest extends AbstractOpBehaviorTest { @@ -30,63 +28,53 @@ public class OpBehaviorFloatNotEqualTest extends AbstractOpBehaviorTest { super(); } -@Test - public void testEvaluateBinaryLong() { + @Test + public void testEvaluateBinaryLong() { OpBehaviorFloatNotEqual op = new OpBehaviorFloatNotEqual(); FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - Assert.assertEquals(0, op.evaluateBinary(1, 8, ff.getEncoding(1.234), ff.getEncoding(1.234))); - Assert.assertEquals(0, op.evaluateBinary(1, 8, ff.getEncoding(-1.234), ff.getEncoding(-1.234))); - Assert.assertEquals(1, op.evaluateBinary(1, 8, ff.getEncoding(-1.234), ff.getEncoding(1.234))); - Assert.assertEquals( - 0, - op.evaluateBinary(1, 8, ff.getEncoding(Double.POSITIVE_INFINITY), - ff.getEncoding(Double.POSITIVE_INFINITY))); - Assert.assertEquals( - 1, - op.evaluateBinary(1, 8, ff.getEncoding(Double.POSITIVE_INFINITY), - ff.getEncoding(Double.NEGATIVE_INFINITY))); - Assert.assertEquals( - 0, - op.evaluateBinary(1, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), - ff.getEncoding(Double.NEGATIVE_INFINITY))); - Assert.assertEquals( - 1, - op.evaluateBinary(1, 8, ff.getEncoding(Double.POSITIVE_INFINITY), - ff.getEncoding(Double.NaN))); + Assert.assertEquals(0, + op.evaluateBinary(1, 8, ff.getEncoding(1.234), ff.getEncoding(1.234))); + Assert.assertEquals(0, + op.evaluateBinary(1, 8, ff.getEncoding(-1.234), ff.getEncoding(-1.234))); + Assert.assertEquals(1, + op.evaluateBinary(1, 8, ff.getEncoding(-1.234), ff.getEncoding(1.234))); + Assert.assertEquals(0, op.evaluateBinary(1, 8, ff.getEncoding(Double.POSITIVE_INFINITY), + ff.getEncoding(Double.POSITIVE_INFINITY))); + Assert.assertEquals(1, op.evaluateBinary(1, 8, ff.getEncoding(Double.POSITIVE_INFINITY), + ff.getEncoding(Double.NEGATIVE_INFINITY))); + Assert.assertEquals(0, op.evaluateBinary(1, 8, ff.getEncoding(Double.NEGATIVE_INFINITY), + ff.getEncoding(Double.NEGATIVE_INFINITY))); + Assert.assertEquals(1, op.evaluateBinary(1, 8, ff.getEncoding(Double.POSITIVE_INFINITY), + ff.getEncoding(Double.NaN))); } -@Test - public void testEvaluateBinaryBigInteger() { + @Test + public void testEvaluateBinaryBigInteger() { OpBehaviorFloatNotEqual op = new OpBehaviorFloatNotEqual(); FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigDecimal a = BigDecimal.valueOf(1.234d); - BigDecimal b = BigDecimal.valueOf(-1.234d); - Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(1, 8, ff.getEncoding(a), ff.getEncoding(a))); - Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(1, 8, ff.getEncoding(b), ff.getEncoding(b))); - Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(1, 8, ff.getEncoding(b), ff.getEncoding(a))); - Assert.assertEquals( - BigInteger.ZERO, - op.evaluateBinary(1, 8, ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY))); - Assert.assertEquals( - BigInteger.ONE, - op.evaluateBinary(1, 8, ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); - Assert.assertEquals( - BigInteger.ZERO, - op.evaluateBinary(1, 8, ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY))); - Assert.assertEquals( - BigInteger.ONE, - op.evaluateBinary(1, 8, ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY), - ff.getEncoding(FloatFormat.BIG_NaN))); + BigFloat a = ff.getBigFloat(1.234d); + BigFloat b = ff.getBigFloat(-1.234d); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(1, 8, ff.getEncoding(a), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ZERO, + op.evaluateBinary(1, 8, ff.getEncoding(b), ff.getEncoding(b))); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(1, 8, ff.getEncoding(b), ff.getEncoding(a))); + Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(1, 8, + ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(false))); + Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(1, 8, + ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(true))); + Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(1, 8, + ff.getBigInfinityEncoding(true), ff.getBigInfinityEncoding(true))); + Assert.assertEquals(BigInteger.ONE, + op.evaluateBinary(1, 8, ff.getBigInfinityEncoding(false), ff.getBigNaNEncoding(false))); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatRoundTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatRoundTest.java index f890681ae0..37eaab782a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatRoundTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatRoundTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -81,44 +80,41 @@ public class OpBehaviorFloatRoundTest extends AbstractOpBehaviorTest { FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(3.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(2.25d)); + a = ff.getEncoding(ff.getBigFloat(2.25d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(2.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(2.75d)); + a = ff.getEncoding(ff.getBigFloat(2.75d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(3.0d).stripTrailingZeros(), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(-2.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.25d)); + a = ff.getEncoding(ff.getBigFloat(-2.25d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(-2.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-2.75d)); + a = ff.getEncoding(ff.getBigFloat(-2.75d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(BigDecimal.valueOf(-3.0d).stripTrailingZeros(), - ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-3.0d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSqrtTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSqrtTest.java index ca5339b0d0..2836a0e4bf 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSqrtTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSqrtTest.java @@ -15,14 +15,12 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; import org.junit.Test; -import ghidra.pcode.floatformat.FloatFormat; -import ghidra.pcode.floatformat.FloatFormatFactory; +import ghidra.pcode.floatformat.*; public class OpBehaviorFloatSqrtTest extends AbstractOpBehaviorTest { @@ -30,8 +28,8 @@ public class OpBehaviorFloatSqrtTest extends AbstractOpBehaviorTest { super(); } -@Test - public void testEvaluateBinaryLong() { + @Test + public void testEvaluateBinaryLong() { OpBehaviorFloatSqrt op = new OpBehaviorFloatSqrt(); @@ -44,19 +42,18 @@ public class OpBehaviorFloatSqrtTest extends AbstractOpBehaviorTest { } -@Test - public void testEvaluateBinaryBigInteger() { + @Test + public void testEvaluateBinaryBigInteger() { OpBehaviorFloatSqrt op = new OpBehaviorFloatSqrt(); FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigDecimal big = BigDecimal.valueOf(2.0); + BigFloat big = ff.getBigFloat(2.0); BigInteger encoding = ff.getEncoding(big); encoding = op.evaluateUnary(8, 8, encoding); - BigDecimal result = ff.getHostFloat(encoding); - Assert.assertEquals("1.414213562373095", result.toString()); - + BigFloat result = ff.getHostFloat(encoding); + Assert.assertEquals("1.414213562373095", ff.round(result).toString()); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSubTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSubTest.java index fd7fd3156e..f0966507c6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSubTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSubTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -75,35 +74,35 @@ public class OpBehaviorFloatSubTest extends AbstractOpBehaviorTest { FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(1.5d)); - BigInteger b = ff.getEncoding(BigDecimal.valueOf(1.25d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(1.5d)); + BigInteger b = ff.getEncoding(ff.getBigFloat(1.25d)); BigInteger result = op.evaluateBinary(8, 8, a, b);// 1.5 - 1.25 - Assert.assertEquals(BigDecimal.valueOf(0.25d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(0.25d), ff.getHostFloat(result)); - a = ff.getEncoding(BigDecimal.valueOf(-1.25d)); + a = ff.getEncoding(ff.getBigFloat(-1.25d)); result = op.evaluateBinary(8, 8, a, b);// -1.25 - 1.25 - Assert.assertEquals(BigDecimal.valueOf(-2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.5d), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = op.evaluateBinary(8, 8, a, b);// +INFINITY - 1.25 - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = op.evaluateBinary(8, 8, a, b);// -INFINITY - 1.25 - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + b = ff.getBigInfinityEncoding(true); result = op.evaluateBinary(8, 8, a, b);// -INFINITY - -INFINITY - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); - b = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + b = ff.getBigInfinityEncoding(false); result = op.evaluateBinary(8, 8, a, b);// -INFINITY - +INFINITY - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); - a = ff.getEncoding(FloatFormat.BIG_NaN); - b = ff.getEncoding(BigDecimal.valueOf(1.25d)); + a = ff.getBigNaNEncoding(false); + b = ff.getEncoding(ff.getBigFloat(1.25d)); result = op.evaluateBinary(8, 8, a, b);// NaN - 1.25 - Assert.assertEquals(FloatFormat.BIG_NaN, ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatTruncTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatTruncTest.java index 5820fe00a4..e8037af847 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatTruncTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatTruncTest.java @@ -15,7 +15,6 @@ */ package ghidra.pcode.opbehavior; -import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; @@ -30,8 +29,8 @@ public class OpBehaviorFloatTruncTest extends AbstractOpBehaviorTest { super(); } -@Test - public void testEvaluateBinaryLong() { + @Test + public void testEvaluateBinaryLong() { OpBehaviorFloatTrunc op = new OpBehaviorFloatTrunc(); @@ -59,31 +58,31 @@ public class OpBehaviorFloatTruncTest extends AbstractOpBehaviorTest { Assert.assertEquals(0, result); } -@Test - public void testEvaluateBinaryBigInteger() { + @Test + public void testEvaluateBinaryBigInteger() { OpBehaviorFloatTrunc op = new OpBehaviorFloatTrunc(); FloatFormat ff = FloatFormatFactory.getFloatFormat(8); - BigInteger a = ff.getEncoding(BigDecimal.valueOf(2.5d)); + BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = op.evaluateUnary(8, 8, a); Assert.assertEquals(BigInteger.valueOf(2), result); - a = ff.getEncoding(BigDecimal.valueOf(-2.5d)); + a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = op.evaluateUnary(8, 8, a); Assert.assertEquals(BigInteger.valueOf(-2), result); - a = ff.getEncoding(FloatFormat.BIG_POSITIVE_INFINITY); + a = ff.getBigInfinityEncoding(false); result = op.evaluateUnary(8, 8, a); Assert.assertEquals(BigInteger.valueOf(Long.MAX_VALUE), result); - a = ff.getEncoding(FloatFormat.BIG_NEGATIVE_INFINITY); + a = ff.getBigInfinityEncoding(true); result = op.evaluateUnary(8, 8, a); Assert.assertEquals(BigInteger.valueOf(Long.MIN_VALUE), result); // TODO: What should the correct result be? - a = ff.getEncoding(FloatFormat.BIG_NaN); + a = ff.getBigNaNEncoding(false); result = op.evaluateUnary(8, 8, a); Assert.assertEquals(BigInteger.ZERO, result); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float10DataTypeTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float10DataTypeTest.java index 6ec505aae9..2eb5822b08 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float10DataTypeTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float10DataTypeTest.java @@ -15,7 +15,7 @@ */ package ghidra.program.model.data; -import java.math.BigDecimal; +import java.math.*; import org.junit.Assert; import org.junit.Test; @@ -46,39 +46,43 @@ public class Float10DataTypeTest extends AbstractGTest { // Really small values + MathContext mc = new MathContext(18, RoundingMode.UP); + bytes = bytes(0, 1, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x00018000000000000000 = approaches 0 value = Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals("5.04315471466814026E-4932", value.toString()); + Assert.assertEquals("5.04315471466814026E-4932", ((BigDecimal) value).round(mc).toString()); bytes = bytes(0x80, 1, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x00018000000000000000 = approaches 0 value = Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals("-5.04315471466814026E-4932", value.toString()); + Assert.assertEquals("-5.04315471466814026E-4932", + ((BigDecimal) value).round(mc).toString()); // Really big values bytes = bytes(0x7f, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7ffe8000000000000000 = approaches +infinity value = Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals("8.92298621517923824E+4931", value.toString()); + Assert.assertEquals("8.92298621517923824E+4931", ((BigDecimal) value).round(mc).toString()); bytes = bytes(0xff, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7ffe8000000000000000 = approaches -infinity value = Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals("-8.92298621517923824E+4931", value.toString()); + Assert.assertEquals("-8.92298621517923824E+4931", + ((BigDecimal) value).round(mc).toString()); // Values within the range of Double bytes = bytes(0x40, 1, 0x20, 0, 0, 0, 0, 0, 0, 0); // 0x40002000000000000000 = approaches -infinity value = Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals(BigDecimal.valueOf(4.5), value); + Assert.assertEquals(BigDecimal.valueOf(4.5), ((BigDecimal) value).stripTrailingZeros()); bytes = bytes(0xc0, 1, 0x20, 0, 0, 0, 0, 0, 0, 0); // 0x40002000000000000000 = approaches -infinity value = Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals(BigDecimal.valueOf(-4.5), value); + Assert.assertEquals(BigDecimal.valueOf(-4.5), ((BigDecimal) value).stripTrailingZeros()); }