0
Answered

Change precision of mp object

Michael_ 5 years ago updated by Pavel Holoborodko 5 years ago 4
Hello.
I got a few questions about the initialisation of mp-numbers and the used precision.

A short example:

mp.Digits(34);

%cuts the number at 34 decimal digits
number34digits = mp('0.123456789123456789123456789123456789') ;

%number with lower precision
number9digits = mp('0.123456789',9);

%Some calculations
number9digits-mp('10^-20')
ans = 0.123456789

number9digits-mp('10^-9')
ans = 0.123456788

number9digits-mp('10^-20',34)
ans = 0.123456789

mp('10^-20')-number9digits
ans = -0.12345678894780576228095458984375

Interestingly this works as well:
number9digits-'10^-9'
ans = 0.123456788

Obviously the calculations are done with the precision of the first number, even the global precision is 34 digits.

%Another calculation

number34digits-number9digits
ans = 1.756510268325021992797067835708226e-10

number9digits-number34digits
ans = -1.75651027e-10

I assume the calculation is done with 34 digits precision and the number9digits is converted to 34 digits. The converted version of number9digits in 34 digits is not 0.1234567890000000000000000000000000.

mp(number9digits,34)
ans = 0.12345678894780576229095458984375

I guess the reason for that is, that the binary number is converted and not the decimal one.

If I define:
number9digits_ = mp('0.123456789',34);

number34digits-number9digits_
ans = 1.23456789123456789123456781439154e-10

The result is different of course, since the number9digits_ was defined with 34 digits precision.

Could you provide a more detailed documentation on this matter? Which precision is acctually used in calculations when numbers with different precision are used?

I was wondering if it is possible to make a function which simply converts a low precision number like

numberlowprecision = mp('1.234',9);

to a higher precision number like

numberhighprecision = mp(numberlowprecision,34)

which is acctually

numberhighprecision = mp('1.234',34);

For double numbers I am able to do that with an work around:

doublenumber = 1.234;

mpnumber = (num2str(doublenumber),34);

I did not find a mp2str function but maybe I missed it.

A question on another matter is the initialisation of mp-arrays. I did not get the syntax yet. I tried:

mparray = mp('[1.23456,1.23456]');
mparray = mp({'1.23456','1.23456'})

Thank you for your answer.

Under review
Hello Michael,

Thank you for your questions (as always)!

1. We overload the 'num2str' function so that it supports the mp(). Same for sprintf and fprintf.
You can use the functions for mp() exactly as with double. 

2. The mp() numbers are stored in binary format, not decimal.
So that when precision of mp() number is increased - we see no decimal zeroes added.

3. 

I was wondering if it is possible to make a function which simply converts a low precision number like
numberlowprecision = mp('1.234',9);

to a higher precision number like
numberhighprecision = mp(numberlowprecision,34)

which is acctually
numberhighprecision = mp('1.234',34);

I am afraid this is not possible for all numbers. It is possible for a narrow set of numbers which have exact binary representation (1/2, etc.), but not in general.

When number is stored with some precision - its accuracy is rounded to the precision specified.
Then we can extend the precision of the number (represent using the higher number of bits), but not the accuracy.
Accuracy is lost and we can only guess what it was. 

That is why it is better to avoid any precision conversions.

We have some additional information about this in our brief user manual: http://goo.gl/NRsaRx

4. The general rule we follow when deal with numbers of different precision - we do the operation with the maximum precision out of two arguments.

However, as I see from your examples - this is not always the case. Checking now...

5. You can check the precision of any mp() entity using function mp.Digits():

a = mp('pi');
mp.Digits(a);

6. As strange as it might seem - lower precision gives no merit in performance.
The fastest mode is quadruple - all others are slower.

Quadruple uses heavy optimization tricks as its size known in advance.
We have no such luxury for arbitrary precision numbers - thus slower execution.

7. 
A question on another matter is the initialisation of mp-arrays. I did not get the syntax yet. I tried:
mparray = mp('[1.23456,1.23456]');
mparray = mp({'1.23456','1.23456'})

We do not support such conversions at the moment.

Element-wise initialization is the only way for such case:

mparray = [mp('1.23456'), mp('1.23456')];

***

Let me know why do you need to change the precision during the computations (iterative, Newton-like schemes?).

Btw, today we have moved closer to proper Bessel functions - we have developed our own FORTRAN to arbitrary precision C++ converter. Now testing.
Thank you for your quick answer.

In my matlab code I read an input file with user-specific data. In the double precision case this is no problem since I create the user-specific data file (it is a struct) and store it. If I need it again, I simply load it.

At the moment I create a new user-specific file for the version in quadruple-precision. In this user-specific file (a struct) I enter all the data with mp objects and the needed precision, for example 34 digits.

Problem is, that I need to make this file all over again when I want to change the precision of all the calculations. At the beginning I simply made the file with 128 digits precision, because I thought all the mp objects are casted to the globally defined precision, for example mp.Digits(34). As you already meationed this is not the case.

I did not try this yet, but maybe it works to do something like this

struct128digits = "a struct which contains mp objects which have been created with 128 digits precision"

save('struct128digits','struct128digits')
clear all;
mp.Digits(34);
load('struct128digits')

I did not test if the loaded struct has a precision of 128 or 34 yet. Or maybe it is possible to do something like this:

struct34digits=mp(struct128digits,34)

Which should be the same compared to a struct which was created in 34 digits.

Ps: Thank you for the effored fixing the bessel functions
struct34digits=mp(struct128digits,34)

Yes, this is the official way of changing the precision of variable and it works perfectly.
It has clear and simple semantic.

The case when operands of one math. operation have different precision - is totally different beast -
don't go that way.
Actually it has been a long-time holywar among developers of arbitrary precision libraries - what precision to use in that case. Both parties - for "minimum" and "maximum" precision have their arguments and no straightforward semantic exists here.

Please also note, all variables stay in precision they were created with, regardless of precision changes made by mp.Digits() later. Same with files - variables are stored/loaded with the original precision they had. 

So that in your case, it is smart idea to store numbers in high precision, and then round them as needed to lower precision upon loading.