precision matlab vpa - matlab

I'm working with an algorithm, which uses hyperbolic functions and in order to get more accurate results from it I need to increase the precision, so I would like to do it by vpa function means, but I'm not quite sure how to implement it. Here some code to clarify the situation further:
x=18; %the hyperbolic relation is valid until x=18
cosh(x)^2-sinh(x)^2
ans = 1
x=19; %the hyperbolic relation is no longer valid
cosh(x)^2-sinh(x)^2
ans = 0
working with the VPA function:
a=vpa('cosh(40)',30); %the hyperbolic relation is valid beyond x=19
b=vpa('sinh(40)',30);
a^2-b^2
ans = 1.00008392333984375
the problem now is that I don't know how to get the value from VPA with a variable of control 'x'
I tried this but it didn't work:
x=40;
a=vpa('cosh(x)',x,30);
b=vpa('sinh(x)',30);
a^2-b^2

When doing symbolic math or variable precision arithmetic one must be careful with with converting between floating-point. In this case, you need to convert your input, x, to variable precision before passing it in to cosh or sinh (otherwise only the output of these will be converted to variable precision). For your example:
x = vpa(40,30);
a = cosh(x);
b = sinh(x);
a^2-b^2
which returns the expected 1.0. I'm not sure where you found the the use of vpa with string inputs, but that form is no longer used (using strings may even result in different results due to different functions being called). Note also that the default setting for digits in current versions of Matlab is 32.

Related

How to force MATLAB to not compute as Inf

I am trying to work through some code that I wrote and one specific line is giving me problems in MATLAB:
Ts = (1+(DatesMod.*Bs)./VolMod).^(VolMod);
VolMod is an array with values on the order of 10^8, DatesMod has a range of values between 700,000 and 740,000, and Bs has a range of values between 0 and 100. Note that this function is mathematically similar to doing lim(n->Inf) (1+B*Dates/n)^n. I understand that this primarily has to do with the methods of allocating numbers on the computer. Is there a clever way I can force it to compute the actual value instead of returning Inf for every value?
Thanks in advance.
Note that the limit
lim(n->Inf) (1+B*Dates/n)^n = exp(B*Dates)
and that exp will overflow to Inf once the argument is greater than 709.9, so there is no real way to compute Ts exactly without arbitrary precision arithmetic.
The best option is probably work in log-precision, e.g. instead of Ts you work with logTs
logTs = VolMod .* log1p((DatesMod.*Bs)./VolMod)
You would then need to rewrite any subsequent expressions to use this without explicitly computing exp(logTs) (as that will overflow).

Using a variable-sized argument in Matlab coder

I want to generate a c++ code for DCT function using Matlab coder. I wrote this simple function and tried to convert it to c++.
function output_signal = my_dct(input_signal)
output_signal = dct(input_signal);
end
When I use a fixed size type for the input argument (such as double 1x64), there is no problem; however, a variable-sized type (such as double 1x:64) for the input argument results in these errors:
The preceding error is caused by: Non-constant expression..
The input to coder.const cannot be reduced to a constant.
Can anyone please help me?
Thanks in advance.
The documentation is a bit vague for DCT in Coder, but it implies that the input size must be a constant power of 2 along the dimension of the transform. From DCT help:
C/C++ Code Generation
Generate C and C++ code using MATLAB® Coder™.
Usage notes and limitations:
C and C++ code generation for dct requires DSP System Toolbox™ software.
The length of the transform dimension must be a power of two. If specified, the pad or truncation value must be constant. Expressions or variables are allowed if their values do not change.
It doesn't directly say that the length of the variable (at least along the dimension being transformed) going into the dct function must be a constant, but given how coder works, it really probably has to be. Since that's the error it's returning, it appears that's a limitation.
You could always modify your calling function to zero pad to a known maximum length, thus making the length constant.
For instance, something like this might work:
function output_signal = my_dct(input_signal)
maxlength = 64;
tinput = zeros(1,maxlength);
tinput(1:min(end, numel(input_signal))) = input_signal(1:min(end, maxlength));
output_signal = dct(tinput);
end
That code will cause tinput to always have a size of 1 by 64 elements. Of course, the output will also always be 64 elements long also, which means it'll be scaled and may have a difference frequency scale than you're expecting.

Accuracy error in binomials using MATLAB?

The value is absolute integer, not a floating point to be doubted, also, it is not about an overflow since a double value can hold until 2^1024.
fprintf('%f',realmax)
179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
The problem I am facing in nchoosek function that it doesn't produce exact values
fprintf('%f\n',nchoosek(55,24));
2488589544741302.000000
While it is a percentage error of 2 regarding that binomian(n,m)=binomial(n-1,m)+binomial(n-1,m-1) as follows
fprintf('%f',nchoosek(55-1,24)+nchoosek(55-1,24-1))
2488589544741301.000000
Ps: The exact value is 2488589544741300
this demo shows
What is wrong with MATLAB?
Your understanding of the realmax function is wrong. It's the maximum value which can be stored, but with such large numbers you have a floating point precision error far above 1. The first integer which can not be stored in a double value is 2^53+1, try 2^53==2^53+1 for a simple example.
If the symbolic toolbox is available, the easiest to implement solution is using it:
>> nchoosek(sym(55),sym(24))
ans =
2488589544741300
There is a difference between something that looks like an integer (55) and something that's actually an integer (in terms of variable type).
The way you're calculating it, your values are stored as floating point (which is what realmax is pointing you to - the largest positive floating point number - check intmax('int64') for the largest possible integer value), so you can get floating point errors. An absolute difference of 2 in a large value is not that unexpected - the actual percentage error is tiny.
Plus, you're using %f in your format string - e.g. asking it to display as floating point.
For nchoosek specifically, from the docs, the output is returned as a nonnegative scalar value, of the same type as inputs n and k, or, if they are different types, of the non-double type (you can only have different input types if one is a double).
In Matlab, when you type a number directly into a function input, it generally defaults to a float. You have to force it to be an integer.
Try instead:
fprintf('%d\n',nchoosek(int64(55),int64(24)));
Note: %d not %f, converting both inputs to specifically integer. The output of nchoosek here should be of type int64.
I don't have access to MATLAB, but since you're obviously okay working with Octave I'll post my observations based on that.
If you look at the Octave source code using edit nchoosek or here you'll see that the equation for calculating the binomial coefficient is quite simple:
A = round (prod ((v-k+1:v)./(1:k)));
As you can see, there are k divisions, each with the possibility of introducing some small error. The next line attempts to be helpful and warn you of the possibility of loss of precision:
if (A*2*k*eps >= 0.5)
warning ("nchoosek", "nchoosek: possible loss of precision");
So, if I may slightly modify your final question, what is wrong with Octave? I would say nothing is wrong. The authors obviously knew of the possibility of imprecision and included a check to warn users when that possibility arises. So the function is working as intended. If you require greater precision for your application than the built-in function provides, it looks as though you'll need to code (or find) something that calculates the intermediate results with greater precision.

evaluate numeric part of a "sym" variable

I need to evaluate numeric part of a "sym" variable in MATLAB(something like "evalf" function in maple) for instance I have this sym variable :
(12*(51*EE*II - 8*39^(1/2)*EE*II))/(AA*ll^4*ro)
"evalf" in maple gives me 12.48019224*EE*II/(AA*ll^4*ro), is there any way to do this in MATLAB?
I think that you're looking for the vpa (variable precision arithmetic) function
syms EE II AA ll ro
y = (12*(51*EE*II - 8*39^(1/2)*EE*II))/(AA*ll^4*ro)
vpa(y)
which returns
ans =
(12.48019215375377223869826038978*EE*II)/(AA*ll^4*ro)
MATLAB has a simplify command, but keep in mind that the symbolic toolbox does not like to evaluate to give decimal, it will try to keep everything in fractional values, since that is more accurate anyway.
syms('EE','AA','ll','II','ro')
simplify((12*(51*EE*II - 8*39^(1/2)*EE*II))/(AA*ll^4*ro)))
This will reduce down into the following
-(12*EE*II*(8*39^(1/2) - 51))/(AA*ll^4*ro)
Whether this is more to your liking is really up to you, but I would suggest keeping things in fractions as opposed to decimal. More accuracy is better.
The eval function might also be of some use to you, but that too will keep it fractional. Using that will give you
(13722116389931*EE*II)/(1099511627776*AA*ll^4*ro)

Why does "pi" become symbolic in MATLAB?

In the Matlab command window I type:
syms f;
s = 2*pi*f*j;
s
which returns
s =
pi*f*2*j
Why is pi is not calculated as 3.141592...?What's wrong with the code I entered into the command window?
Welcome to symbolic math where you get exact answers as opposed to floating-point approximations. If you just want to "get a number" you can use non-symbolic functions and operations or you can convert symbolic results back to floating-point.
For example:
syms f
s = pi*f*2*j
s2 = subs(s,f,2)
s3 = double(s2)
Alternatively, you can use variable precision arithmetic to represent pi as a decimal approximation of a specified level in a symbolic expression:
syms f
s = vpa(pi)*f*j
See the documentation for vpa for further details. You can also use the sym function to achieve similar things.
However, you can lose some of the power of symbolic math if you convert to a decimal or floating point representation too soon. For example, compare the difference between the following expressions:
sin(pi) % 1.224646799147353e-16
sin(vpa(pi)) % -3.2101083013100396069547145883568e-40
sin(sym(pi)) % 0, sin(sym(1)*pi) and sin(sym(pi,'r')) also return zero
Only the last one will be fully cancelled out of an expression, thus simplifying it.