diff --git a/MSVisualStudio/v17/CoinUtilsUnitTest/CoinUtilsUnitTest.vcxproj b/MSVisualStudio/v17/CoinUtilsUnitTest/CoinUtilsUnitTest.vcxproj index 52b7dc8f..6a76a2cb 100644 --- a/MSVisualStudio/v17/CoinUtilsUnitTest/CoinUtilsUnitTest.vcxproj +++ b/MSVisualStudio/v17/CoinUtilsUnitTest/CoinUtilsUnitTest.vcxproj @@ -157,6 +157,7 @@ + diff --git a/src/CoinRational.cpp b/src/CoinRational.cpp index ddf8a956..9fb660cc 100644 --- a/src/CoinRational.cpp +++ b/src/CoinRational.cpp @@ -29,8 +29,8 @@ bool CoinRational::nearestRational_(double val, double maxdelta, int64_t maxdnom { double intpart; if (floor(val)==val) { - numerator_ = val; - denominator_ = 1.0; + numerator_ = (int64_t) val; + denominator_ = 1; return true; } double fracpart = fabs(modf(val, &intpart)); @@ -83,7 +83,7 @@ bool CoinRational::nearestRational_(double val, double maxdelta, int64_t maxdnom assert(inaccuracy <= maxdelta); } #endif - numerator_ += std::abs(intpart) * denominator_; + numerator_ += ((int64_t) std::abs(intpart)) * denominator_; if (val < 0) numerator_ *= -1; #if DEBUG_X > 1 diff --git a/src/CoinRational.hpp b/src/CoinRational.hpp index e73d5e9a..16c4a4b8 100644 --- a/src/CoinRational.hpp +++ b/src/CoinRational.hpp @@ -40,6 +40,14 @@ class COINUTILSLIB_EXPORT CoinRational bool nearestRational_(double val, double maxdelta, int64_t maxdnom); }; +//############################################################################# +/** A function that tests the methods in the class. The + only reason for it not to be a member method is that this way it doesn't + have to be compiled into the library. And that's a gain, because the + library should be compiled with optimization on, but this method should be + compiled with debugging. */ +void CoinRationalUnitTest(); + #endif /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2 diff --git a/test/CoinRationalTest.cpp b/test/CoinRationalTest.cpp new file mode 100644 index 00000000..49d96c6b --- /dev/null +++ b/test/CoinRationalTest.cpp @@ -0,0 +1,165 @@ +// This code is licensed under the terms of the Eclipse Public License (EPL). + +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include "CoinUtilsConfig.h" + +#ifdef COINUTILS_HAS_STDINT_H +#include +#endif + +#include +#include +#include "CoinRational.hpp" + +void +CoinRationalUnitTest() +{ + + // Test default constructor + { + CoinRational a; // 0/1 + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 0); + assert(a.getDenominator() == 1); + } + + // Requires int64_t + // Test constructor with assignment + { + CoinRational a(4294967295, 4294967296); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 4294967295); + assert(a.getDenominator() == 4294967296); + } + + // Requires int64_t + // Test constructor with assignment + { + CoinRational a(9223372036854775807, 4294967299); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 9223372036854775807); + assert(a.getDenominator() == 4294967299); + } + + // Requires int64_t + // Test constructor with nearestRational calls + { + CoinRational a(2147483699.5, 0.00001, 4294967299); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 4294967399); + assert(a.getDenominator() == 2); + } + + // Test constructor with nearestRational calls + { + CoinRational a(-3.0, 0.0001, 100); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == -3); + assert(a.getDenominator() == 1); + } + + { + CoinRational a(3.0, 0.0001, 100); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 3); + assert(a.getDenominator() == 1); + } + + { + // return 0/1 if best is more than maxdelta tolerance + CoinRational a(0.367879441, 0.0001, 100); // 1/e + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 32); + assert(a.getDenominator() == 87); + } + + { + CoinRational a(10.367879441, 0.0001, 100); // 10 + 1/e + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 902); + assert(a.getDenominator() == 87); + } + + { + // return 0/1 if best is more than maxdelta tolerance + CoinRational a(0.367879441, 0.000001, 100); // 1/e + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 0); + assert(a.getDenominator() == 1); + } + + { + CoinRational a(3.0 / 7.0, 0.0001, 100); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 3); + assert(a.getDenominator() == 7); + } + + { + CoinRational a(7.0 / 3.0, 0.0001, 100); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 7); + assert(a.getDenominator() == 3); + } + + { + double sqrt13 = sqrt(13); + CoinRational a(sqrt13, 0.01, 20); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 18); + assert(a.getDenominator() == 5); + } + + { + double sqrt13 = sqrt(13); + CoinRational a(sqrt13, 0.002, 30); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 101); + assert(a.getDenominator() == 28); + } + + { + CoinRational a(0.25, 0.1, 3); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 1); + assert(a.getDenominator() == 3); + } + + { + CoinRational a(0.605551, 0.003, 30); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 17); + assert(a.getDenominator() == 28); + } + + { + CoinRational a(0.605551, 0.001, 30); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 20); + assert(a.getDenominator() == 33); // oops, should be at most 30. + } + + { + CoinRational a(0.58496250072, 0.00001, 253); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 179); + assert(a.getDenominator() == 306); // oops, should be at most 253. Expected 148/253, but this is apparently on purpose. + } + + { + CoinRational a(19.0/11.0, 0.02, 10); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == 12); + assert(a.getDenominator() == 7); + } + + { + CoinRational a(-19.0 / 11.0, 0.02, 10); + std::cout << "Testing " << a.getNumerator() << " / " << a.getDenominator() << std::endl; + assert(a.getNumerator() == -12); + assert(a.getDenominator() == 7); + } +} diff --git a/test/Makefile.am b/test/Makefile.am index c2d334cc..3d86a2f2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -20,6 +20,7 @@ unitTest_SOURCES = \ CoinMpsIOTest.cpp \ CoinPackedMatrixTest.cpp \ CoinPackedVectorTest.cpp \ + CoinRationalTest.cpp \ CoinShallowPackedVectorTest.cpp \ unitTest.cpp diff --git a/test/Makefile.in b/test/Makefile.in index f6a71839..3d382dc4 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -123,7 +123,7 @@ am_unitTest_OBJECTS = CoinLpIOTest.$(OBJEXT) \ CoinIndexedVectorTest.$(OBJEXT) \ CoinMessageHandlerTest.$(OBJEXT) CoinModelTest.$(OBJEXT) \ CoinMpsIOTest.$(OBJEXT) CoinPackedMatrixTest.$(OBJEXT) \ - CoinPackedVectorTest.$(OBJEXT) \ + CoinPackedVectorTest.$(OBJEXT) CoinRationalTest.$(OBJEXT) \ CoinShallowPackedVectorTest.$(OBJEXT) unitTest.$(OBJEXT) unitTest_OBJECTS = $(am_unitTest_OBJECTS) am__DEPENDENCIES_1 = @@ -155,6 +155,7 @@ am__depfiles_remade = ./$(DEPDIR)/CoinDenseVectorTest.Po \ ./$(DEPDIR)/CoinModelTest.Po ./$(DEPDIR)/CoinMpsIOTest.Po \ ./$(DEPDIR)/CoinPackedMatrixTest.Po \ ./$(DEPDIR)/CoinPackedVectorTest.Po \ + ./$(DEPDIR)/CoinRationalTest.Po \ ./$(DEPDIR)/CoinShallowPackedVectorTest.Po \ ./$(DEPDIR)/unitTest.Po am__mv = mv -f @@ -361,6 +362,7 @@ unitTest_SOURCES = \ CoinMpsIOTest.cpp \ CoinPackedMatrixTest.cpp \ CoinPackedVectorTest.cpp \ + CoinRationalTest.cpp \ CoinShallowPackedVectorTest.cpp \ unitTest.cpp @@ -439,6 +441,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CoinMpsIOTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CoinPackedMatrixTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CoinPackedVectorTest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CoinRationalTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CoinShallowPackedVectorTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unitTest.Po@am__quote@ # am--include-marker @@ -579,6 +582,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/CoinMpsIOTest.Po -rm -f ./$(DEPDIR)/CoinPackedMatrixTest.Po -rm -f ./$(DEPDIR)/CoinPackedVectorTest.Po + -rm -f ./$(DEPDIR)/CoinRationalTest.Po -rm -f ./$(DEPDIR)/CoinShallowPackedVectorTest.Po -rm -f ./$(DEPDIR)/unitTest.Po -rm -f Makefile @@ -635,6 +639,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/CoinMpsIOTest.Po -rm -f ./$(DEPDIR)/CoinPackedMatrixTest.Po -rm -f ./$(DEPDIR)/CoinPackedVectorTest.Po + -rm -f ./$(DEPDIR)/CoinRationalTest.Po -rm -f ./$(DEPDIR)/CoinShallowPackedVectorTest.Po -rm -f ./$(DEPDIR)/unitTest.Po -rm -f Makefile diff --git a/test/unitTest.cpp b/test/unitTest.cpp index acae4732..a0f347b1 100644 --- a/test/unitTest.cpp +++ b/test/unitTest.cpp @@ -16,6 +16,7 @@ #include "CoinPragma.hpp" #include "CoinFinite.hpp" #include "CoinError.hpp" +#include "CoinRational.hpp" #include "CoinHelperFunctions.hpp" #include "CoinSort.hpp" #include "CoinShallowPackedVector.hpp" @@ -189,6 +190,9 @@ int main (int argc, const char *argv[]) testingMessage( "Testing CoinError\n" ); CoinErrorUnitTest(); + testingMessage("Testing CoinRational\n"); + CoinRationalUnitTest(); + testingMessage( "Testing CoinShallowPackedVector\n" ); CoinShallowPackedVectorUnitTest();