Open ofloveandhate opened 1 year ago
the tests for z2, z3, z4, and z5 all fail in the above code.
This is a continuation of #308 , and in turn #75
more testing reveals that if the default precision is less than the max of that of the two operands, we'll get the max precision of the two operands back.
i think uniform precision environments are probably my goal, as anything else seems difficult to control. i'll wait for someone to reply before posting more.
thanks for your attention!!! 🚀
OK there is a bug, but not the one you think.
How this should work is that preserve_target_precision
preserves the precision of the LHS of the = sign and all the others preserve the precision of the RHS. For example all the asserts in the following example pass for me:
using namespace boost::multiprecision;
mpfr_float a{ 2 }, b{ 3 }, z;
a.precision(40);
b.precision(50);
z.precision(20);
mpfr_float::thread_default_variable_precision_options(boost::multiprecision::variable_precision_options::preserve_target_precision);
z = a * b;
std::cout << z.precision() << std::endl;
assert(z.precision() == 20);
mpfr_float::thread_default_variable_precision_options(boost::multiprecision::variable_precision_options::preserve_source_precision);
z = a * b;
assert(z.precision() == 50);
z.precision(60);
mpfr_float::thread_default_variable_precision_options(boost::multiprecision::variable_precision_options::preserve_target_precision);
z = a * b;
assert(z.precision() == 60);
mpfr_float::thread_default_variable_precision_options(boost::multiprecision::variable_precision_options::preserve_source_precision);
z = a * b;
assert(z.precision() == 50);
Note the call to thread_default_variable_precision_options
. Unfortunately here's the bug: default_variable_precision_options
forgets to set the options for the current thread!! So your calls are basically having no effect at all. I'll fix this shortly.
While I wait for a fix (and for it to get distributed), should I rely on the thread*
functions?
Yes the thread_* functions are actually working!
But of course, uniform precision is the easiest model, it just requires a fair bit of discipline.
I have a related question. When making a new variable and the default precision is not equal to that of any operand, what should be the precision of a new variable? Specifically, for the following code
mpfr_float::thread_default_precision(50);
mpfr_float x("0.01234567890123456789012345678901234567890123456789");
mpfr_float::thread_default_precision(60);
mpfr_float y("0.12345678901234567890123456789012345678901234567890123456789");
BOOST_CHECK_EQUAL(y.precision(), 60);
mpfr_float::thread_default_precision(30);
mpfr_float z = x*y; // what should be the precision of `z`, and for which policies?
what should the precision of z be? Does it depend on the precision options?
I think APPoT is meaningless in this scenario because the target doesn't exist, in which case the precision should be one of:
The only thing the current default precision is used for for the precision of a new variable.
In the case of an expression, the expression is always evaluated at the precision of it's largest component (albeit which components are selected is determined by the policies when they're not all floats), the policies then determine what happens next - preservation of that precision via for example preserve_source_precision
or rounding to the precision of the target variable via preserve_target_precision
. In this case the target variable is assumed to have current default precision: I don't see there should be any difference between:
mpfr_float z = a*b;
and
mpfr_float z;
z = a*b;
Ok, thank you. Your explanation was very helpful.
I'm still working on understanding the policies implemented for mixed precision arithmetic. i'm at boost 1.81 as installed from homebrew on a mac M1.
I have the following code that I think doesn't produce expected results. Namely, I make two variables
x
andy
at precision 50 and 60 respectively. Then I make a variablez
at precision 70, and default precision is 70. Then I computex*y
with the various policies. For all of them,z=x*y
leavesz
with the precision it started with. Specifically, I think that for all policies exceptpreserve_target_precision
the precision ofz
should be60
after. But in all cases the precision ofz
is the current default precision; the precision of the target does not depend on the precision of the operands.Is this the expected behaviour? am I not correctly setting the policy? I used the doc page on variable precision as my guide, and I think what i have is correct.
test code: