From: kanschat Date: Wed, 30 Nov 2011 20:41:10 +0000 (+0000) Subject: add float reproducibility option X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4b4adbf85ca77fbe07f9155bdeb7a0e4e70729c2;p=dealii-svn.git add float reproducibility option git-svn-id: https://svn.dealii.org/trunk@24782 0785d39b-7218-0410-832d-ea1e28bc413d --- diff --git a/deal.II/include/deal.II/base/logstream.h b/deal.II/include/deal.II/base/logstream.h index 3f7cff804c..5023e59d03 100644 --- a/deal.II/include/deal.II/base/logstream.h +++ b/deal.II/include/deal.II/base/logstream.h @@ -54,8 +54,33 @@ DEAL_II_NAMESPACE_OPEN *
  • deallog.pop() when leaving that stage entered with push. * * + *

    LogStream and reproducible regression test output

    + * + * Generating reproducible floating point output for regression tests + * is mildly put a nightmare. In order to make life a little easier, + * LogStream implements a few features that try to achieve such a + * goal. These features are turned on by calling test_mode(), and it + * is not recommended to use them in any other environment. Right now, + * LogStream implements the following: + * + *
      + *
    1. A double number very close to zero will end up being output in + * exponential format, although it has no significant digits. The + * parameter #double_threshold determines which numbers are too close + * to zero to be considered nonzero. + *
    2. For float numbers holds the same, but with a typically larger + * #float_threshold. + *
    3. Rounded numbers become unreliable with inexact + * arithmetics. Therefore, adding a small number before rounding makes + * results more reproducible, assuming that numbers like 0.5 are more + * likely than 0.49997. + *
    + * It should be pointed out that all of these measures distort the + * output and make it less accurate. Therefore, they are only + * recommended if the output needs to be reproducible. + * * @ingroup textoutput - * @author Guido Kanschat, Wolfgang Bangerth, 1999, 2003 + * @author Guido Kanschat, Wolfgang Bangerth, 1999, 2003, 2011 */ class LogStream { @@ -87,6 +112,26 @@ class LogStream */ void detach (); + /** + * Setup the logstream for + * regression test mode. + * + * This sets the parameters + * #double_threshold, + * #float_threshold, and #offset + * to nonzero values. The exact + * values being used have been + * determined experimentally and + * can be found in the source + * code. + * + * Called with an argument + * false, switches off + * test mode and sets all + * involved parameters to zero. + */ + void test_mode (bool on=true); + /** * Gives the default stream (std_out). */ @@ -259,15 +304,29 @@ class LogStream /** * Output double precision * numbers through this - * stream. This function - * eliminates floating point - * numbers smaller than - * #double_threshold, which can - * be changed using - * threshold_double(). + * stream. + * + * If they are set, this function + * applies the methods for making + * floating point output + * reproducible as discussed in + * the introduction. */ LogStream & operator << (const double t); + /** + * Output single precision + * numbers through this + * stream. + * + * If they are set, this function + * applies the methods for making + * floating point output + * reproducible as discussed in + * the introduction. + */ + LogStream & operator << (const float t); + /** * Treat ostream * manipulators. This passes on @@ -383,9 +442,55 @@ class LogStream /** * Threshold for printing double - * values. + * values. Every number with + * absolute value less than this + * is printed as zero. */ double double_threshold; + + /** + * Threshold for printing float + * values. Every number with + * absolute value less than this + * is printed as zero. + */ + float float_threshold; + + /** + * An offset added to every float + * or double number upon + * output. This is done after the + * number is compared to + * #double_threshold or #float_threshold, + * but before rounding. + * + * This functionality was + * introduced to produce more + * reproducable floating point + * output for regression + * tests. The rationale is, that + * an exact output value is much + * more likely to be 1/8 than + * 0.124997. If we round to two + * digits though, 1/8 becomes + * unreliably either .12 or .13 + * due to machine accuracy. On + * the other hand, if we add a + * something above machine + * accuracy first, we will always + * get .13. + * + * It is safe to leave this + * value equal to zero. For + * regression tests, the function + * test_mode() sets it to a + * reasonable value. + * + * The offset is relative to the + * magnitude of the number. + */ + double offset; + /** * Flag for printing thread id. */ @@ -493,14 +598,6 @@ inline LogStream & LogStream::operator<< (const double t) { - // for doubles, we want to make - // sure that if a number is smaller - // than a given threshold, then we - // simply print zero (the default - // threshold is zero, but can be - // changed for automated testsuite - // runs) - // // we have to make sure that we // don't catch NaN's and +-Inf's // with the test, because for these @@ -509,12 +606,38 @@ LogStream::operator<< (const double t) // both t<=0 and t>=0 are false at // the same time, which can't be // said for any other number - if ((std::fabs(t) > double_threshold) - || - (! (t<=0) && !(t>=0))) + if (! (t<=0) && !(t>=0)) + print (t); + else + if (std::fabs(t) < double_threshold) + print ('0'); + else + print(t*(1.+offset)); + + return *this; +} + + + +inline +LogStream & +LogStream::operator<< (const float t) +{ + // we have to make sure that we + // don't catch NaN's and +-Inf's + // with the test, because for these + // denormals all comparisons are + // always false. thus, for a NaN, + // both t<=0 and t>=0 are false at + // the same time, which can't be + // said for any other number + if (! (t<=0) && !(t>=0)) print (t); else - print('0'); + if (std::fabs(t) < float_threshold) + print ('0'); + else + print(t*(1.+offset)); return *this; } diff --git a/deal.II/source/base/logstream.cc b/deal.II/source/base/logstream.cc index 2c8c1839e9..e853162167 100644 --- a/deal.II/source/base/logstream.cc +++ b/deal.II/source/base/logstream.cc @@ -55,7 +55,8 @@ LogStream::LogStream() std_out(&std::cerr), file(0), std_depth(10000), file_depth(10000), print_utime(false), diff_utime(false), - last_time (0.), double_threshold(0.), old_cerr(0) + last_time (0.), double_threshold(0.), float_threshold(0.), + offset(0), old_cerr(0) { prefixes.push("DEAL:"); std_out->setf(std::ios::showpoint | std::ios::left); @@ -107,6 +108,24 @@ LogStream::~LogStream() } +void +LogStream::test_mode(bool on) +{ + if (on) + { + double_threshold = 1.e-10; + float_threshold = 1.e-7; + offset = 1.e-7; + } + else + { + double_threshold = 0.; + float_threshold = 0.; + offset = 0.; + } +} + + LogStream & LogStream::operator<< (std::ostream& (*p) (std::ostream&)) {