How to simplify a symbolic and numeric mixed expression in Matlab - matlab

I have a symbolic and numeric mixed expression:
(3145495418313256125*sin(11334310783410932061962315977/17437937757178560512000000000)*cos(theta))/85568392920039424
where theta is a symbolic variable. I want to simplify this expression such that all the numeric numbers and their math operation results are changed to double.

In terms of data types, you can't mix floating point and symbolic values. However, you can use variable precision arithmetic so that the values are represented in decimal form. Using vpa:
syms theta
y1 = (3145495418313256125*sin(11334310783410932061962315977/17437937757178560512000000000)*cos(theta))/85568392920039424
y2 = vpa(y1)
which returns
y2 =
22.24607614528243677915796931637*cos(theta)
The data type (class) of y2 is still sym. See the digits function to adjust the number of significant digits.
If you want to work in actual floating point you'll need to convert your symbolic expression into a function. You can automate that procedure by using the confusingly-named matlabFunction:
thetafun = matlabFunction(y1)
which returns a function using double precision variables:
thetafun =
#(theta)cos(theta).*2.224607614528244e1
The anonymous function thetafun can then be called just like any function, e.g., thetafun(0.5).

You can make use of coeffs command to achieve the desired:
f=2*cos(theta)/3+5*sin(theta)/19
c_f=coeffs(f);
fraction_c_f=double(c_f);
ans = [0.2632 0.6667]

Related

The parameter of zeros

I want to create a matrix by "zeros([numbers,3])"
syms x;
numbers=symsum(x,x,1,5);
zeros([numbers,3])
Here is the error: The size must be a number.
How to create a matrix like this "zeros([numbers,3])"
This is because numbers is of sym class. Convert it to double first. i.e. use XX=zeros(double(numbers),3); instead.
But still there is no need to use Symbolic Math Toolbox here. What you're doing can be done more simply as:
numbers = sum(1:5);
XX = zeros(numbers,3)

How to pass a Matlab vector variable to a MuPAD function?

I want to use the stats::swGOFT function in MuPAD. I have a numerical vector called r. I used
feval(symengine, 'stats::swGOFT', r);
The error was
Error using mupadengine/feval (line 157)
MuPAD error: Error: Some data are of invalid type.
So I tried a more direct way, which worked:
feval(symengine, 'stats::swGOFT', 1,2,3,4);
But this didn't work:
feval(symengine, 'stats::swGOFT', [1,2,3,4]);
My variable r is a 1146-by-1 double vector. Obviously I can't manually input all the numbers. So, how to pass the vector variable r to the MuPAD function stats::swGOFT?
MuPAD is not Matlab. From the current version documentation for stats::swGOFT, it appears that this function requires a list, as opposed to an array (what Matlab uses). Many MuPAD functions automatically coerce inputs to the desired format, but that doesn't seem to occur in this case. You have several options if you want to call this function from Matlab using numeric values – here's a simple one that will work for both floating point and symbolic numeric values:
r = randn(1146,1);
rStr = char(sym(r(:).'));
feval(symengine, 'stats::swGOFT', rStr(9:end-2))
This one should perform the string conversion more quickly for large datasets of floating point values using sprintf:
r = randn(1146,1);
rStr = ['[' sprintf('%.17g', r(1)) sprintf(',%.17g', r(2:end)) ']'];
feval(symengine, 'stats::swGOFT', rStr)
Since you're converting to a string yourself, you might as well convert the above to use evalin directly:
r = randn(1146,1);
rStr = [ sprintf('%.17g', r(1)) sprintf(',%.17g', r(2:end)) ];
evalin(symengine, ['stats::swGOFT([' rStr '])'])

Error using integral: A and B must be floating-point scalars

I want to evaluate the simple example of integral
a = max(solve(x^3 - 2*x^2 + x ==0 , x));
fun = #(x) exp(-x.^2).*log(x).^2;
q = integral(fun,0,a)
and the error is
Error using integral (line 85)
A and B must be floating-point scalars.
Any tips? The lower limit of my integral must be a function, not a number.
The Matlab command solve returns symbolic result. integral accepts only numeric input. Use double to convert symbolic to numeric. As your code is written now, already max should throw an error due to symbolic input. The following works.
syms x;
a = max(double(solve(x^3 - 2*x^2 + x)));
fun = #(x) exp(-x.^2).*log(x).^2;
q = integral(fun,0,a)
Output: 1.9331.
the lower limit of my integral must be a function, not a number
integral is a numeric integration routine; the limits of integration must be numeric.
Check values of a by mouse over in breakpoint or removing the ; from the end of the line so it prints a. Based on the error, a is not a scalar float. You might need another max() or double() statement to transform the vector to a single value.
Solve Help : http://www.mathworks.com/help/symbolic/solve.html
Integral Help : http://www.mathworks.com/help/ref/integral.html

How to have MATLAB display answer in decimals with e instead of fractions

So im using MATLAB to calculate the coefficient of an equation and it keeps displaying fractions as the constants instead of decimal form like xxe-x
My code is below
bt = 0.03175;
bpzt = 0.0078;
ht = 0.003;
w = 50; % frequency in Hz
pnic = 8908; % density of nickel
Enic = 200e9; % Young's modulus of nic
L = 0.3048; % Length of canitlever beam in m
syms hn
inertia = (1/12)*bt*ht^3 + (1/2)*bpzt*ht^2*hn - (1/2)*bpzt*ht*hn^2 + (2/3)*bpzt*hn^3
area = (bt*ht - 2*hn*bt + 2*bpzt*hn);
You are using the symbolic math toolbox. You have to convert any symbolic variable back to a numerical one. Use double(area) to get a double value of your symbolic variable area. You can use the function single, too.
But be aware that hn has to get a value first, otherwise it cannot be determined.
Documentation: http://www.mathworks.com/help/symbolic/double.html
To format this output, use the usual Matlab tools. In your case format short e
More details: http://www.mathworks.com/help/matlab/matlab_prog/display-format-for-numeric-values.html
In R2014b, this line:
inertia = (1/12)*bt*ht^3 + (1/2)*bpzt*ht^2*hn - (1/2)*bpzt*ht*hn^2 + (2/3)*bpzt*hn^3
returns
(13*hn^3)/2500 - (863307622649607*hn^2)/73786976294838206464 + (5304162033559185*hn)/151115727451828646838272 + 5527208847278085/77371252455336267181195264
which is a symbolic expression with numeric values represented exactly as rational fractions (even though they may have started out as decimal values in your code). You can convert this using vpa
vpa(inertia)
which returns:
0.0052*hn^3 - 0.000011699999999999999788190263583232*hn^2 + 0.000000035099999999999996664653271376613*hn + 0.000000000071437500000000005341045287673881
The length/precision of the decimal values depends on digits. Displaying this in an exponential-style format (xxe-x) is not an option for any symbolic math expression or value unless you write your own function to parse the string and do the conversion.
To convert this to a vectorized double-precision floating point function, you can use the terribly-named matlabFunction – matlabFunction(inertia) returns:
#(hn)hn.*3.51e-8-hn.^2.*1.17e-5+hn.^3.*5.2e-3+7.143750000000001e-11
But if you're doing this, I'd wonder why you were working with symbolic math in the first place and if it's possible to do everything in much faster double precision.
Keep in mind that if you want to convert to any kind of decimal form, variable precision or floating-point, in many cases you will lose precision. However, if you just want to view the result or perform fourth calculations if double precision, then it should be fine.

Matlab dec2bin gives wrong values

I'm using Matlab's dec2bin to convert decimal number to binary string. However, I'm getting wrong results. For example:
>> dec2bin(13339262925365424727)
ans =
1011100100011110100101001111010011000111111100011011000000000000
I checked both in a C++ implementation and in wolfram alpha and the correct result is:
1011100100011110100101001111010011000111111100011011001001010111
Is there any problem with my usage of Matlab's desc2bin?
Thanks,
Gil.
Your code is equivalent to:
x=13339262925365424727;
dec2bin(x)
but if you check the value of x, you will notice that it outruns double precision. The number is simply to large to be stored in a 64bit double. The precision is 2^11, check eps(x)
To deal with large numbers, using vpa from the symbolic toolbox is a good option, is this available?
Here is a solution using vpa:
function l=ldec2bin(x)
if x>2^52
head=floor(x/2^52);
tail=x-head*2^52;
l=[ldec2bin(head),dec2bin(double(tail),52)];
else
l=dec2bin(double(x));
end
end
usage:
>> ldec2bin(vpa('13339262925365424727'))
ans =
1011100100011110100101001111010011000111111100011011001001010111
/Update:
I came across a much shorter implementation of dec2bin for symbolic variables:
>> sdec2bin=#(x)(feval(symengine,'int2text',x,2))
sdec2bin =
#(x)(feval(symengine,'int2text',x,2))
>> sdec2bin(sym('13339262925365424727'))
ans =
1011100100011110100101001111010011000111111100011011001001010111
The integer seems to long, maybe you should try de2bi function;
http://www.mathworks.com/help/comm/ref/de2bi.html
Assuming that the input is less than intmax('uint64'), as in the example, here is a solution that doesn't require the Symbolic Math toolbox. This supports two input arguments, matching dec2bin, is vectorized, and should be much faster:
function s=int2bin(d,n)
%INT2BIN Convert nonnegative integer to a binary string
if isempty(d)
s = '';
return;
end
d = d(:);
if ~isinteger(d) || any(d < 0)
error('int2bin:InvalidIntegerInput',...
'First input must be a nonnegative integer class array.');
end
if nargin < 2
n = 1
else
n = round(double(n));
end
m = double(nextpow2(max(d)));
s = [repmat('0',length(d),n-m) rem(bsxfun(#bitshift,d,1-m:0),2)+'0'];
If you don't mind a bit less performance and prefer a one-line anonymous function, try:
int2bin = #(d,n)char(rem(bsxfun(#bitshift,d(:),1-max(n,double(nextpow2(max(d(:))))):0),2)+'0');
or this one that uses bitand instead of bitshift:
int2bin = #(d,n)char(~~bsxfun(#bitand,d(:),2.^(max(n,nextpow2(max(d(:)))):-1:0))+'0');
All versions above assume that d is a nonnegative integer class variable, e.g., uint64(13339262925365424727), and that n is a nonnegative numeric scalar. You can find full-featured int2bin and bin2int functions on my GitHub.