The logged_adaptor type
is used in conjunction with number
and some other backend type: it acts as a thin wrapper around some other
backend to class number
and logs all the events that take place on that object. Before any number
operation takes place, it calls log_prefix_event
with the arguments to the operation (up to 4), plus a string describing
the operation. Then after the operation it calls log_postfix_event
with the result of the operation, plus a string describing the operation.
Optionally, log_postfix_event
takes a second result argument: this occurs when the result of the operation
is not a number, for example
when fpclassify is called,
log_postfix_event will
be called with result1
being the argument to the function, and result2
being the integer result of fpclassify.

The default versions of log_prefix_event
and log_postfix_event do
nothing, it is therefore up to the user to overload these for the particular
backend being observed.

This type provides numeric_limits
support whenever the template argument Backend does so.

This type is particularly useful when combined with an interval number
type - in this case we can use log_postfix_event
to monitor the error accumulated after each operation. We could either
set some kind of trap whenever the accumulated error exceeds some threshold,
or simply print out diagnostic information. Using this technique we can
quickly locate the cause of numerical instability in a particular routine.
The following example demonstrates this technique in a trivial algorithm
that deliberately introduces cancellation error:

#include<boost/multiprecision/mpfi.hpp>#include<boost/multiprecision/logged_adaptor.hpp>#include<iostream>#include<iomanip>//// Begin by overloading log_postfix_event so we can capture each arithmetic event as it happens://namespaceboost{namespacemultiprecision{template<unsignedD>inlinevoidlog_postfix_event(constmpfi_float_backend<D>&val,constchar*event_description){// Print out the (relative) diameter of the interval:usingnamespaceboost::multiprecision;number<mpfr_float_backend<D>>diam;mpfi_diam(diam.backend().data(),val.data());std::cout<<"Diameter was "<<diam<<" after operation: "<<event_description<<std::endl;}template<unsignedD,classT>inlinevoidlog_postfix_event(constmpfi_float_backend<D>&,constT&,constchar*event_description){// This version is never called in this example.}}}intmain(){usingnamespaceboost::multiprecision;typedefnumber<logged_adaptor<mpfi_float_backend<17>>>logged_type;//// Test case deliberately introduces cancellation error, relative size of interval// gradually gets larger after each operation://logged_typea=1;a/=10;for(unsignedi=0;i<13;++i){logged_typeb=a*9;b/=10;a-=b;}std::cout<<"Final value was: "<<a<<std::endl;return0;}

When we examine program output we can clearly see that the diameter of
the interval increases after each subtraction: