Low precision of floats?

2 views (last 30 days)
Martin Clever
Martin Clever on 27 Aug 2023
Commented: Martin Clever on 29 Aug 2023
I want to calculate digamma(x),1<x<2 with high precision. I wrote the code
psi(vpa(3/2, 100))
ans = 
0.036489973978576520559023667001244
Now I wanted to check the result with the wolfram alpha result of 0.036489973978576520559023667001244... But when I write
x = vpa(0.03648997397857652055, 100)
x = 
0.03648997397857652036368136805322137661278247833251953125
The stored number is completly wrong after 18 digits (0.03648997397857652036...). How can I save floats with more than 18 digits? Is there a better way to achieve what I am trying to do?

Accepted Answer

Walter Roberson
Walter Roberson on 27 Aug 2023
It is documented that int64() and uint64() calls with a single literal numeric parameter are "syntax" that lead to the values being parsed as 64 bit. And it is documented that there are hexadecimal and binary constant formats that are syntax for getting particular numeric datatypes with specific bit patterns.
But other than that... semantically, every (non-binary, non-hex) numeric constant is treated as a double precision constant at parse time. Sematically,
A = uint8(42)
is modeled as passing double precision 42.0 to the uint8() type conversion method of class double. That might not be how it is handled internally -- possibly internally the code is transformed as an assignment of a uint8 constant -- but the int64() and uint64() and bit and hex constants are the only documented exceptions.
Therefore, when you have the call
x = vpa(0.03648997397857652055, 100)
then the closest double precision representation of 0.03648997397857652055 is formed, and that double precision value is passed to vpa() along with the double precision representation of 100.
int64() and uint64() are the only documented calls that affect the interpretation of parameters before the functions are "called". (It would not surprise me if in practice single() did the same thing, just not documented.)
Other than int64() and uint64(), the evaluation model of MATLAB is always to evaluate the parameters first, left to right, and only then to look at the call -- so in the MATLAB model, at the time the parameter 0.03648997397857652055 is being evaluated, MATLAB has no idea it is going to be calling a symbolic function. As far as MATLAB is concerned, you have asked for the same thing as
anonymous_variable_342356 = 0.03648997397857652055;
anonymous_variable_7652346 = 100;
x = vpa(anonymous_variable_342356, anonymous_variable_7652346 )
The solutions are the one that @Adam Danz posted,
vpa('0.036489973978576520559023667001244',100)
or alternately
vpa(sym('0.036489973978576520559023667001244'),100)
or
vpa(str2sym('0.036489973978576520559023667001244'),100)

More Answers (2)

Adam Danz
Adam Danz on 27 Aug 2023
vpa('0.036489973978576520559023667001244',100)
ans = 
0.036489973978576520559023667001244

Steven Lord
Steven Lord on 28 Aug 2023
Don't call vpa first. Perform the calculation symbolically then use vpa on the result.
onePointFive = sym(3/2)
onePointFive = 
y = psi(onePointFive)
y = 
Let's check your statement "Now I wanted to check the result with the wolfram alpha result of 0.036489973978576520559023667001244... But when I write"
vpa(y, 200)
ans = 
0.036489973978576520559023667001244432806840395339565892952872746128345029282945897851326282715415875401365590709051546051668455513997196049710484499084924539885044524600319791881711979959621394810658384
Looks good to me.
  1 Comment
Martin Clever
Martin Clever on 29 Aug 2023
But how does this help me, confirming that the approximation is correct? I would still need to check if the 200 digits are correct?
Nonetheless, thank you for your time and the symbolic trick is neat in itself

Sign in to comment.

Products


Release

R2023a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!