Boost logo

Boost :

From: Terje Slettebø (tslettebo_at_[hidden])
Date: 2003-05-04 23:01:36


As was said in another posting: And now for something completely different.

The Interval library, which has recently been accepted into Boost, has been
mentioned regarding the discussion of an SI units/quantity library. I've
read the docs for this, and it appears that no special support is needed to
use this with a quantity library, provided the library may use any type as
the underlying type. In that case, you can just use interval<T> rather than
T, and you can use it with interval arithmetic.

Interval arithmetic is useful to specify precision, and other cases where
you're dealing with an interval.

When it comes to the output operator, it displays an interval in the form
"[<lower>, <upper>]". This is fine as a general output. However, if the
interval is used to determine precision, it may be more useful to print the
value, with the number of significant digits, instead. For example:

std::cout << interval<double>(1.231, 1.233); // Prints "1.23"

std::cout << interval<double>(1.2345678911, 1.2345678913); // Prints
"1.234567891"

Below is an ouput operator which works like this, and an example program
with output after it.

--- Start ---

#include <boost/interval.hpp>
#include <boost/io/ios_state.hpp>
#include <cmath>

namespace boost {

template<class T, class CharType, class CharTraits>
std::basic_ostream<CharType, CharTraits> &operator<<
  (std::basic_ostream<CharType, CharTraits> &stream, const interval<T>
&value)
{
  const T abs_lower=value.lower()>=0 ? value.lower() : -value.lower();
  const T abs_upper=value.upper()>=0 ? value.upper() : -value.upper();
  const T lower_mantissa=value.lower()/std::pow(10,
static_cast<int>(std::log10(abs_lower)));
  const T upper_mantissa=value.upper()/std::pow(10,
static_cast<int>(std::log10(abs_upper)));

  const T difference=upper_mantissa-lower_mantissa;

  const double exponent=std::log10(difference);

  boost::io::ios_precision_saver state(stream,-exponent+1);

  return stream << (value.upper()+value.lower())/2;
}

} // namespace boost

// Test program

#include <iostream>
#include <iomanip>

int main()
{
  std::cout << std::setprecision(std::numeric_limits<double>::digits10)
            << 1.0/3.0 << '\n'
            << '\n'
            << boost::interval<double>(1.231,1.233) << '\n'
            << boost::interval<double>(-1.233,-1.231) << '\n'
            << boost::interval<double>(1.231e100,1.233e100) << '\n'
            << boost::interval<double>(-1.233e100,-1.231e100) << '\n'
            << '\n'
            << boost::interval<double>(1.2345678911,1.2345678913) << '\n'
            << boost::interval<double>(-1.2345678913,-1.2345678911) << '\n'
            << boost::interval<double>(1.2345678911e100,1.2345678913e100) <<
'\n'
            << boost::interval<double>(-1.2345678913e100,-1.2345678911e100)
<< '\n';
}

--- End ---

Output:

0.333333333333333

1.23
-1.23
1.23e+100
-1.23e+100

1.234567891
-1.234567891
1.234567891e+100
-1.234567891e+100

Could this be a useful addition to the Interval library?

Since there is an output operator in boost/interval/io.hpp, this might be
called boost/interval/io_precision.hpp.

An input operator, working in the same way - determining the interval from
the number of digits given - might also be provided. It might for example be
written using Spirit to parse the number.

Regards,

Terje


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk