MATLAB digits precision - matlab

I have MATLAB code:
clear;
clc;
syms x;
f=log(x)*sin(x^2);
a=vpa(subs(f,x,2),100)
fprintf('a=%.100f\n',a);
doublea=double(a);
fprintf('a=%.100f\n',doublea);
and the result is
a =
-0.5245755158634217064842071630254785076113576311088295152384038229263081153172372089356742060202648499
a=-0.5245755158634216600000000000000000000000000000000000000000000000000000000000000000000000000000000000
doublea =
-0.5246
a=-0.5245755158634216600000000000000000000000000000000000000000000000000000000000000000000000000000000000
>>
Why if I use fprintf the decimal precision is only up to 16 digits, even though I use 100 digits precision?
Also why if I convert a to double then a is only up to 16 digits?
Can it cause an error in the calculation if I want use more than 16 digits precision? How to fix it?

Have you tried using num2str or vpa coupled with disp?
a1 = vpa(a,100);
disp(a1);
Or
disp(['a = ' num2str(a,100)])
Edit: Hadi's link in the comments has a great explanation.

Related

how can I show more than 15 significant digits for each entry in matlab?

I want to calculate numbers in Matlab.
how can I show more than 15 significant digits for each entry in Matlab?
a = 1:10;
x = (773712524553590618513 + (a * 8864385670));
Using the vpa function in the Symbolic Math Toolbox more than 16 digits can be shown.
format long e
a=1:10;
x = (773712524553590618513+(a*8864385670));
vpa(x)
Edit: Any clarification between the implications of using syms against variable-point-precision (vpa) for a, 773712524553590618513 and 8864385670 in this case is much appreciated. Seems that using vpa() on each item would have some error propagation.
a = sym(1:10);
f = sym(773712524553590618513)+(a*sym(8864385670));
Significant_Digits = 32;
x = vpa(f,Significant_Digits)

Matlab reading numbers with higher precision

I have made this scripts that calculates the frequency of a given dataset, but matlab is not precise enough, is it possible to make matlab read in more accurat numbers and not cut off the numbers? I want it to use 8 digits (0.12345678) instead of 4 (0.1234) that is does now
fid = fopen('forceCoeffs.dat','rt');
A = textscan(fid, '%f%f%f%f%f%f', 'HeaderLines',9,'Collect', 9);
A = A{1};
fclose(fid);
t = A(:,1);
Fs = 1/(A(1,1));
x = A(:,2)
x = detrend(x,0);
xdft = fft(x);
freq = 0:Fs/length(x):Fs/2;
xdft = xdft(1:length(x)/2+1);
plot(freq,abs(xdft));
[~,I] = max(abs(xdft));
fprintf('Maximum occurs at %d Hz.\n',freq(I));
File: https://drive.google.com/file/d/0B9CEsYCSSZUSb1JmcHRkbFdWYUU/view?usp=sharing
Thank you for including the forceCoeffs.dat file as it allowed me to run your code. Here is an explanation of what you are seeing.
First I want to point out that MATLAB is not rounding anything. You can check the data type of A to ensure you have enough precision.
>> class(A)
ans =
double
And since you are reading in the file using %f for each column, MATLAB will use all the bits provided by the double type. Ok, now take a look at the contents of your file. The first column has only 2 decimals of precision at most.
0.05 -7.013874e-09 1.410717e+02 -6.688450e-02 -3.344226e-02 -3.344224e-02
...
349.95 -1.189524e-03 1.381022e+00 -2.523909e-01 -1.273850e-01 -1.250059e-01
350 -1.423947e-03 1.380908e+00 -2.471767e-01 -1.250123e-01 -1.221644e-01
Since no more is needed MATLAB only prints four decimal places when you look at the variable in the variable explorer. Try looking at one of the other columns to see what I am talking about. I commented out the A = A{1} part of your code and looked at the second column. When clicking on the number you see the full precision.
You can use a long type to display 16 digits
To get more than 4 digits precision, you can use
format long
However, to get exactly 8 digits, you need to round it. If your number is a then let use:
format long
round(1e8*a)*1e-8

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.

How to add leading zeros in MatLab (number formatting)?

Here is a very specific example
>> S = num2str(12345,'%6.0e')
S =
1e+04
and that's just great since I want only my first digit and an exponential notation. However I also want to add leading zeros to the exponent in order to fill the width, but I cannot quite find the way to get the following...
1e+004
Meanwhile it's very straighforward to pad the significant digits with leading zeros
>> S = num2str(12345,'%06.0e')
S =
01e+04
So is there an appropriate formatting for what I want? Or a trick to accomplish it quickly?
The exponent is always a zero-padded two-digit value. To add, say, two zeros you can use
regexprep(num2str(12345, '%6.0e'), '\+', '\+00')
and achieve
ans =
1e+0004
Edit: To cover negative exponents you may use
regexprep(num2str(0.12345, '%6.0e'), '(\+|\-)', '$100')
to achieve
ans =
1e-0001
And, to cover three-digit exponents
regexprep(num2str(1e-100, '%6.0e'), '(\+|\-)(\d{2,3})$', {'$10$2', '$10$2'})
ans =
1e-0100
regexprep(num2str(1e-10, '%6.0e'), '(\+|\-)(\d{2,3})$', {'$10$2', '$10$2'})
ans =
1e-0010
Well, I think you have to edit, what you say you want is wat you get :D
however, if I understood correctly what you are looking for, this function will help you
function printX(x, digits)
format = sprintf('\t%%.%de', digits - 1);
strcat(inputname(1), ' = ', sprintf(format, x))
end