In Matlab, when printing using e such as fprintf('%10.5e\n', pi/100) one will get the result to be 3.14159e-02. However, what if I want the number to have a leading zero such as 0.314159e-1? How can I manage this with Matlab?
The reason I ask is that I am trying to print to a file which I need to have leading zeros. Otherwise, I would not care.
Thanks.
I don't think there is any clever way to do it:
your_number = pi;
['0.' strrep(sprintf('%10.5e',your_number*10), '.', '')]
>> ans =
0.314159e+01
my solution is pretty crude but this is just to illustrate. You can do it yourself with a small function that will look for the relevant strings in the number, trim it after e, add 0. in the beginning and increse by 1 the exponent at the end, for example:
function b=fooo(a)
b=a;
k1 = strfind(a, '.');
k2 = strfind(a, 'e-');
suffix=num2str(str2num(b(k2+1:k2+3))+1);
b(k2+1:end)=[];
b(k1)=[];
b=['0.' b suffix];
where an input like
ans=fooo(sprintf('%10.5e\n', pi/100))
will yield the answer:
ans =
0.314159e-1
Related
This is a question about the function nchoosek in Matlab.
I want to find nchoosek(54,25), which is the same as 54C25. Since the answer is about 10^15, I originally use int64. However the answer is wrong with respect to the symbolic one.
Input:
nchoosek(int64(54),int64(25))
nchoosek(sym(54),sym(25))
Output:
1683191473897753
1683191473897752
You can see that they differ by one. This is not really an urgent problem since I now use sym. However can someone tell me why this happens?
EDIT:
I am using R2013a.
I take a look at the nchoosek.m, and find that if the input are in int64, the code can be simplified into
function c = nchoosek2(v,k)
n = v; % rename v to be n. the algorithm is more readable this way.
classOut = 'int64';
nd = double(n);
kd = double(k);
nums = (nd-kd+1):nd;
dens = 1:kd;
nums = nums./dens; %%
c = round(prod(nums));
c = cast(c,classOut);
end
However, the outcome of int64(prod(nums./dens)) is different from prod(sym(nums)./sym(dens)) for me. Is this the same for everyone?
I don't have this problem on R2014a:
Numeric
>> n = int64(54);
>> k = int64(25);
>> nchoosek(n,k)
ans =
1683191473897752 % class(ans) == int64
Symbolic
>> nn = sym(n);
>> kk = sym(k);
>> nchoosek(nn,kk)
ans =
1683191473897752 % class(ans) == sym
% N!/((N-K)! K!)
>> factorial(nn) / (factorial(nn-kk) * factorial(kk))
ans =
1683191473897752 % class(ans) == sym
If you check the source code of the function edit nchoosek.m, you'll see it specifically handles the case of 64-bit integers using a separate algorithm. I won't reproduce the code here, but here are the highlights:
function c = nchoosek(v,k)
...
if int64type
% For 64-bit integers, use an algorithm that avoids
% converting to doubles
c = binCoef(n,k,classOut);
else
% Do the computation in doubles.
...
end
....
end
function c = binCoef(n,k,classOut)
% For integers, compute N!/((N-K)! K!) using prime factor cancellations
...
end
In 2013a this can be reproduced...
There is as #Amro shows a special case in nchoosek for classOut of int64 or unit64,
however in 2013a this is only applied when the answer is between
flintmax (with no argument) and
double(intmax(classOut)) + 2*eps(double(intmax(classOut)))
which for int64 gives 9007199254740992 & 9223372036854775808, which the solution does not lie between...
If the solution had fallen between these values it would be recalculated using the subfunction binCoef
for which the help states: For integers, compute N!/((N-K)! M!) using prime factor cancellations
The binCoef function would have produced the right answer for the given int64 inputs
In 2013a with these inputs binCoef is not called
Instead the "default" pascals triangle method is used in which:
Inputs are cast to double
The product of the vector ((n-k+1):n)./(1:k) is taken
this vector contains k double representations of fractions.
So what we have is almost certainly floating point error.
What can be done?
Two options I can see;
Make your own function based on the code in binCoef,
Modify nchoosek and remove && c >= flintmax from line 81
Removing this expression will force Matlab to use the more accurate integer based calculation for inputs of int64 and uint64 for any values within their precision. This will be slightly slower but will avoid floating point errors, which are rightfully unexpected when working with integer types.
Option one - should be fairly straight forward...
Option two - I recommend keeping an unchanged backup of the original function, or makeing a copy of the function with the modification and use that instead.
folks,
I am wondering if it is possible to write the following function of r as an inline function in matlab. I tried to include the condition as a separate factor such as *(r>a) and I got NaN due to the division of 1/r^3 when r is 0.
I fould a simple way out. It's basically what Shai and Jigg suggested, i.e. using an extra multiplicative factor of (r>a).
To get rid of NaN, we just need to add eps to the denominator of 1/r3, i.e.
1/(r+eps)^3 *(r>a)
First, you haven't stated what should actually happen if r = 0. Mathematically the term gets infinity. I assumed you rather want to set it to zero. And what should happen for r = a? Just another ill-defined case, are you sure your formula is correct?
If you have the Statistics Toolbox you can use nansum. If not, I'd say there is no way around to write your own function similar to nansum, which can't be done inline.
r = -5:1:5;
a = 1;
R = 42; %// rest of your function
%// not working, or removing of nan afterwards required
X = #( r ) (r>=a).*(a./r).^3*R;
%// inline solution with statistics toolbox
Y = #( r ) arrayfun(#(x) nansum( (x>=a)*(a/x)^3*R ), r);
output = [X(r)' Y(r)']
nansum is not vectorized, if you still want to use it for vectors wrap it into arrayfun.
The code of nansum does exactly what was suggested in the comments (output(isnan(output))=0), I'm probably not allowed to copy&paste it here. It filters out all NaN and then sums the input. Use open nansum to have insight.
As pointed out by Jigg, similar functions like nanmean would do the trick as well.
You can try
chi = 1; %// arbitrary value
a = 1; %// arbitrary value
theta = pi/3; %// arbitrary value
nu = #( r ) (r>a).*( (chi/3).*((a.^3)./(r.^3)).*(3*cos(theta).^2 -1);
Let's say I have a random variable a=1.2400, and I want to print it with four significant figures, i.e., 1.240. How would I go about that?
fprintf('%0.4g',a) % drops rightmost zero
fprintf('%0.3f',a) % give too many sig figs if a >= 10
Using '%g' drops the important zeros, and with '%f' I can only specify the number of digits after the decimal, which results in too many significant figures if, say, a=10.04. I'm not too familiar with formatting ,but there has to be a simple method. I haven't found it in my searches.
If the values to be printed are all less than 10000, you can do the following. (Sorry, only tested in octave.)
octave:62> a = 1.24
a = 1.2400
octave:63> sprintf('%.*f\n', 3-floor(log10(abs(a))), a)
ans = 1.240
octave:64> a = 234.56
a = 234.56
octave:65> sprintf('%.*f\n', 3-floor(log10(abs(a))), a)
ans = 234.6
For more about the expression floor(log10(abs(a))), see How can I get the exponent of each number in a np.array?
If you don't mind exponential notation, another alternative is to use '%.3e' to always get the same number of signficant digits:
octave:70> a = 1.24
a = 1.2400
octave:71> sprintf('%.3e\n', a)
ans = 1.240e+00
octave:72> a = 234.56
a = 234.56
octave:73> sprintf('%.3e\n', a)
ans = 2.346e+02
I decided to build on the answer by Warren, and I wrote a function that should work for both small and large numbers alike. Perhaps someone will improve on this, but I am pleased with it.
function str=sigfigstr(a,sigfigs)
numdecimal = floor(log10(abs(a)));
if sigfigs - numdecimal < 0
str=sprintf('%.0f',round(a,sigfigs,'significant'));
else
str=strip(sprintf('%.*f\n', sigfigs-floor(log10(abs(a))), a));
end
Here are a few examples if it in action in Matlab
>> sigfigstr(.000012431634,3)
ans = '0.0000124'
>> sigfigstr(26666,3)
ans = '26700'
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
I'm making some matrix computation in matlab. What looks strange (to me) is that I get results like
(8700286382685973*cos(q5)*sin(q4))/9007199254740992 + sin(q5)*((43220913799951902644522757965203*cos(q4))/730750818665451459101842416358141509827966271488 - 291404338770025/1125899906842624)
but matlab does not simplify the result. I already tried to use functions like simplify, simple,fix but none of them gave the desired result.
Any suggestion on what function should I use?
Simplify does only "exact" manipulations. What you need is a command that kills small terms in your expression. In Mathematica "Chop" takes care of that. Try to google it.
As #Lucas suggested, you can use vpa and digits in matlab, for example if the expression above is A (sym) then:
vpa(A,3) % digits is set to 3
ans =
0.966*cos(q5)*sin(q4) + sin(q5)*(5.91e-17*cos(q4) - 0.259)
And then you can either see the numbers for themselves and chop them, or use something like:
function result = significant(x, n)
% significant(x, n) rounds number x to n number of significant figures
s = floor(log10(abs(x)));
shift = 10^(n-1);
mant = round(x*shift/(10^s)) / shift;
result = mant * 10^s;
Try doing one of these commands before your evaluation:
format longe
format shorte