I am writing a mesh smoother in Matlab for a particular CFD code. The requirements for the mesh data file are very strict, and so the number format must be very specific. The definition for one quadrilateral element is as follows (Where the 2nd row is the x coordinates and 3rd row is y coordinates).
ELEMENT 14 [ 1Q] GROUP 0
5.000000 10.00000 10.00000 5.000000
2.000000 2.000000 4.500000 4.500000
As you can see, each number takes up exactly 8 characters. Once the whole mesh has been passed through my smoother, I need to write the numbers back to a file. the closest I've gotten to this number format is with the following operator:
%#7.7g
I don't think I can use %f, as this specifies the number of digits after the decimal, which in my case varies (I have coordinates that go from less than one to over 100). the only issue that this operator is giving me is when I have numbers less than one, it only retains 7 sig figs, and the number ends up being 9 characters long; for example:
0.9313373
Does anyone know the correct operator, or have a workaround? Much appreciated.
Single format spec:
If you can live with only 4 digit precision (decimal part after the .) out of your 8 characters, and if the mesh reading program can handle padding 0 (i.e. if it can read values like 007.2365 properly), then the simplest and quickest option is to use only the format specifier.
For example, let's define an input a with different order of magnitude:
a=[ 1 234 7 ;
12 2 0.123456789 ;...
5 2.36 0.0024 ] ;
Your highest number is 234, so that leaves 4 digits for the fractional part. If you accept that precision for all the numbers in your Matrix, then you're all set with a simple instruction:
fmt='%08.4f %08.4f %08.4f\n'; %// hard coded format specifier
sprintf(fmt,a.') %'// we transpose a to keep the same shape in the output since sprintf is column major.
ans =
001.0000 234.0000 007.0000
012.0000 002.0000 000.1235
005.0000 002.3600 000.0024
If you don't know in advance what will be the maximum order of magnitude of your data you can set the format specifier programmatically:
nDigitTotal = 8 ;
nmax = ceil( log10(max(a(:))) ) ; %// max order of magnitude of numbers in "a"
f = sprintf('%%0%d.%df',nDigitTotal,nDigitTotal-nmax-1) ; %// format spec for 1 number
fmt = [f '\t' f '\t' f '\n'] ; %// format spec for a line of 3 numbers
s = sprintf(fmt,a.')
Will give the same result as above. Add a check to make sure there are no extreme values in your matrix which will eat your precision.
Individual format spec:
Lastly, if that precision and/or the leading zero do not work for you, you can resort to a more elaborate solution. I quite like the idea from excaza of setting a mask to specify the precision for each number. I'll produce my own version, very slightly different, which account for numbers at any precision and allow array output. However, if you end up using this solution give credit to excaza since he was the inspiration for this evolution:
a = a.' ; %'// transpose from beginning/ thats done
nDigitTotal = 8; %// Total number of characters
mask = nDigitTotal(ones(size(a))) ; %// Create mask
nOrder = floor( log10(a) ) ; %// find order of magnitude of each element in the matrix
mask = mask - nOrder.*(nOrder>0) -1 ; %// adjust mask according to "nOrder" (only for nOrder>0)
temp = [mask(:)';a(:)']; %// Stack the vectors and weave them
f = '%7.*f' ; %// basic format spec
fmt = [f '\t' f '\t' f '\n'] ; %// build your line
sprintf(fmt,temp) %// go for it
will give you:
ans =
1.0000000 234.00000 7.0000000
12.000000 2.0000000 0.1234568
5.0000000 2.3600000 0.0024000
note: replace the tabulation ('\t') with normal whitespace (' ') in the format specifier separator depending on what your meshing software is expecting.
This is the only workaround I could think of:
A = [1.12341234 .12341234 20.12341234 5 10];
% Create a precision mask
maxwidth = 8; % Max width, characters
mask = maxwidth(ones(size(A))) - 1; % Initialize mask, account for decimal
mask(A < 1) = maxwidth - 2;
% Stack the vectors and weave them
temp = [mask(:)';A(:)'];
temp = temp(:);
test = sprintf('%#7.*g ', temp);
Which returns:
test =
1.123412 0.123412 20.12341 5.000000 10.00000
It's an annoying extra step but we can utilize sprintf's ability to take an asterisk in order to refer to an argument in the input list. Due to how my sprintf call and test case are set up, I wove the mask and data together so sprintf sees the precision specifier and data alternating. The temp(:) call isn't necessary, if you pass the original temp matrix to sprintf it will do the same thing since it reads the data column-major. I added it in so the behavior is more explicit.
How to formulate the sprintf call for your actual printing routine will depend on what you're doing, but this should at least help you on your way.
Edit1: To expand, what the above is doing is equivalent to:
a = sprintf('%#7.*g ', temp(1), temp(2));
b = sprintf('%#7.*g ', temp(3), temp(4));
c = sprintf('%#7.*g ', temp(5), temp(6));
d = sprintf('%#7.*g ', temp(7), temp(8));
e = sprintf('%#7.*g ', temp(9), temp(10));
test = [a b c d e];
Edit2: Updated to account for integer values
Edit3: Note that this currently will only work for positive numbers
Related
I have a vector of doubles and I want to see what are the exact numbers inside the vector I get in format long.
1.0e+03 *
-0.002202883146567
1.182072110137121
-0.002242966651629
-0.000584787748712
0.022251505213305
0.037460846794487
Can I make some adjusment so that I can directly see the number, rounded to let's say the 5th or 6th element after the decimal point, whenever I type the name of the variable?
fprintf('%.6f\n', 0.037460846794487)
It'll round 0.037460846794487 to 6 decimal places as shown:
>> fprintf('%.6f\n', 0.037460846794487)
0.037461
Or you can also use sprintf('%.6f\n', 0.037460846794487) , particularly, if you want to save the rounded off output in a variable.
>> a=sprintf('%.6f\n', 0.037460846794487)
a =
0.037461
and for the matrix you mentioned, you can make the following adjustment:
%Your matrix
A = 1.0e+03 * [ -0.002202883146567 ;
1.182072110137121 ;
-0.002242966651629 ;
-0.000584787748712 ;
0.022251505213305 ;
0.037460846794487 ];
A = sprintf('%.6f\n', A) %Adjusted to 6 decimal digits
Is there a way to convert a decimal number between $0$ and $1$ that is not integer to base 4 in Matlab? E.g. if I put 2/5 I want to get 0.12121212... (with some approximation I guess)
The function dec2base only works for integers.
Listed in this post is a vectorized approach that works through all possible combinations of digits to select the best one for the final output as a string. Please note that because of its very nature of creating all possible combinations, it would be memory intensive and slower than a recursive approach, but I guess it could be used just for fun or educational purposes!
Here's the function implementation -
function s = dec2base_float(d,b,nde)
%DEC2BASE_FLOAT Convert floating point numbers to base B string.
% DEC2BASE_FLOAT(D,B) returns the representation of D as a string in
% base B. D must be a floating point array between 0 and 1.
%
% DEC2BASE_FLOAT(D,B,N) produces a representation with at least N decimal digits.
%
% Examples
% dec2base_float(2/5,4,4) returns '0.1212'
% dec2base_float(2/5,3,6) returns '0.101211'
%// Get "base power-ed scaled" digits
scale = b.^(-1:-1:-nde);
%// Calculate all possible combinations
P = dec2base(0:b^nde-1,b,nde)-'0';
%// Get the best possible combination ID. Index into P with it and thus get
%// based converted number with it
[~,idx] = min(abs(P*scale(:) - d));
s = ['0.',num2str(P(idx,:),'%0.f')];
return;
Sample runs -
>> dec2base_float(2/5,4,4)
ans =
0.1212
>> dec2base_float(2/5,4,6)
ans =
0.121212
>> dec2base_float(2/5,3,6)
ans =
0.101211
This question already has answers here:
matlab plot histogram indicating sum of each character inside a file
(2 answers)
Closed 7 years ago.
I have 400 files, each one contains about 500000 character, and those 500000 characters consists only from about 20 letters. I want to make a histogram indicating the most 10 letters used (x-axis) and number of times each letter is used (y-axis). I wrote this code which has missing thing which is I want to know each bar is corresponding to which letter. What should I add on the code ? You can change the whole code, but keeping this is better for me. provide me the whole code so I can copy it directly to a script and run it.
i = 1;
z = zeros(1, 10);
for i=1:400
j = num2str(i);
file_name = strcat('part',j,'txt');
file_id = fopen(file_name);
part = fread(file_id, inf, 'uchar');
h = hist(part,10);
z = z + h;
fclose(file_id);
end
First of all, your use of hist is wrong. hist(data,10) will create a histogram from data that consists of 10 bins, so a bin will correspond to more than one character in your files.
A way to solve this would be to use hist on predefined bins like:
bins = 1:255; % define the bins for hist
histSum = zeros(numel(bins),1);
for file=1:10;
data = randi(25,100) + 'a'; %Generate random data - letters between 'a' and 'z'
data = reshape(T,numel(T),1); % Make it a vector
histSum = histSum + hist(data,bins)';
end
Note that you have to define your bins to accommodate all possible values, therefore ranging from 1 to 255
Problem : How do I use a continuous map - The Link1: Bernoulli Shift Map to model binary sequence?
Concept :
The Dyadic map also called as the Bernoulli Shift map is expressed as x(k+1) = 2x(k) mod 1. In Link2: Symbolic Dynamics, explains that the Bernoulli Map is a continuous map and is used as the Shift Map. This is explained further below.
A numeric trajectory can be symbolized by partitioning into appropriate regions and assigning it with a symbol. A symbolic orbit is obtained by writing down the sequence of symbols corresponding to the successive partition elements visited by the point in its orbit. One can learn much about the dynamics of the system by studying its symbolic orbits. This link also says that the Bernoulli Shift Map is used to represent symbolic dynamics.
Question :
How is the Bernoulli Shift Map used to generate the binary sequence? I tried like this, but this is not what the document in Link2 explains. So, I took the numeric output of the Map and converted to symbols by thresholding in the following way:
x = rand();
y = mod(2* x,1) % generate the next value after one iteration
y =
0.3295
if y >= 0.5 then s = 1
else s = 0
where 0.5 is the threshold value, called the critical value of the Bernoulli Map.
I need to represent the real number as fractions as explained here on Page 2 of Link2.
Can somebody please show how I can apply the Bernoulli Shift Map to generate symbolized trajectory (also called time series) ?
Please correct me if my understanding is wrong.
How do I convert a real valued numeric time series into symbolized i.e., how do I use the Bernoulli Map to model binary orbit /time series?
You can certainly compute this in real number space, but you risk hitting precision problems (depending on starting point). If you're interested in studying orbits, you may prefer to work in a rational fraction representation. There are more efficient ways to do this, but the following code illustrates one way to compute a series derived from that map. You'll see the period-n definition on page 2 of your Link 2. You should be able to see from this code how you could easily work in real number space as an alternative (in that case, the matlab function rat will recover a rational approximation from your real number).
[EDIT] Now with binary sequence made explicit!
% start at some point on period-n orbit
period = 6;
num = 3;
den = 2^period-1;
% compute for this many steps of the sequence
num_steps = 20;
% for each step
for n = 1:num_steps
% * 2
num = num * 2;
% mod 1
if num >= den
num = num - den;
end
% simplify rational fraction
g = gcd(num, den);
if g > 1
num = num / g;
den = den / g;
end
% recover 8-bit binary representation
bits = 8;
q = 2^bits;
x = num / den * q;
b = dec2bin(x, bits);
% display
fprintf('%4i / %4i == 0.%s\n', num, den, b);
end
Ach... for completeness, here's the real-valued version. Pure mathematicians should look away now.
% start at some point on period-n orbit
period = 6;
num = 3;
den = 2^period-1;
% use floating point approximation
x = num / den;
% compute for this many steps of the sequence
num_steps = 20;
% for each step
for n = 1:num_steps
% apply map
x = mod(x*2, 1);
% display
[num, den] = rat(x);
fprintf('%i / %i\n', num, den);
end
And, for extra credit, why is this implementation fast but daft? (HINT: try setting num_steps to 50)...
% matlab vectorised version
period = 6;
num = 3;
den = 2^period-1;
x = zeros(1, num_steps);
x(1) = num / den;
y = filter(1, [1 -2], x);
[a, b] = rat(mod(y, 1));
disp([a' b']);
OK, this is supposed to be an answer, not a question, so let's answer my own questions...
It's fast because it uses Matlab's built-in (and highly optimised) filter function to handle the iteration (that is, in practice, the iteration is done in C rather than in M-script). It's always worth remembering filter in Matlab, I'm constantly surprised by how it can be turned to good use for applications that don't look like filtering problems. filter cannot do conditional processing, however, and does not support modulo arithmetic, so how do we get away with it? Simply because this map has the property that whole periods at the input map to whole periods at the output (because the map operation is multiply by an integer).
It's daft because it very quickly hits the aforementioned precision problems. Set num_steps to 50 and watch it start to get wrong answers. What's happening is the number inside the filter operation is getting to be so large (order 10^14) that the bit we actually care about (the fractional part) is no longer representable in the same double-precision variable.
This last bit is something of a diversion, which has more to do with computation than maths - stick to the first implementation if your interest lies in symbol sequences.
If you only want to deal with rational type of output, you'll first have to convert the starting term of your series into a rational number if it is not. You can do that with:
[N,D] = rat(x0) ;
Once you have a numerator N and a denominator D, it is very easy to calculate the series x(k+1)=mod(2*x(k), 1) , and you don't even need a loop.
for the part 2*x(k), it means all the Numerator(k) will be multiplied by successive power of 2, which can be done by matrix multiplication (or bsxfun for the lover of the function):
so 2*x(k) => in Matlab N.*(2.^(0:n-1)) (N is a scalar, the numerator of x0, n is the number of terms you want to calculate).
The Mod1 operation is also easy to translate to rational number: mod(x,1)=mod(Nx,Dx)/Dx (Nx and Dx being the numerator and denominator of x.
If you do not need to simplify the denominator, you could get all the numerators of the series in one single line:
xn = mod( N.*(2.^(0:n-1).'),D) ;
but for visual comfort, it is sometimes better to simplify, so consider the following function:
function y = dyadic_rat(x0,n)
[N,D] = rat(x0) ; %// get Numerator and Denominator of first element
xn = mod( N.*(2.^(0:n-1).'),D) ; %'// calculate all Numerators
G = gcd( xn , D ) ; %// list all "Greatest common divisor"
y = [xn./G D./G].' ; %'// output simplified Numerators and Denominators
If I start with the example given in your wiki link (x0=11/24), I get:
>> y = dyadic_rat(11/24,8)
y =
11 11 5 2 1 2 1 2
24 12 6 3 3 3 3 3
If I start with the example given by Rattus Ex Machina (x0=3/(2^6-1)), I also get the same result:
>> y = dyadic_rat(3/63,8)
y =
1 2 4 8 16 11 1 2
21 21 21 21 21 21 21 21
I am calculating the Local Ternary Pattern of an image. My code is given below. Am I going in the right direction or not?
function [ I3 ] = LTP(I2)
m=size(I2,1);
n=size(I2,2);
for i=2:m-1
for j=2:n-1
J0=I2(i,j);
I3(i-1,j-1)=I2(i-1,j-1)>J0;
end
end
I2 is the image LTP is applied to.
This isn't quite correct. Here's an example of LTP given a 3 x 3 image patch and a threshold t:
(source: hindawi.com)
The range that you assign a pixel in a window to 0 is when the threshold is between c - t and c + t, where c is the centre intensity of the pixel. Therefore, because the intensity is 34 in the centre of this window, the range is between [29,39]. Any values that are beyond 39 get assigned 1 and any values that are below 29 get assigned -1. Once you determine the ternary codes, you split up the codes into upper and lower patterns. Basically, any values that get assigned a -1 get assigned 0 for upper patterns and any values that get assigned a -1 get assigned 1 for lower patterns. Also, for the lower pattern, any values that are 1 from the original window get mapped to 0. The final pattern is reading the bit pattern starting from the east location with respect to the centre (row 2, column 3), then going around counter-clockwise. Therefore, you should probably modify your function so that you're outputting both lower patterns and upper patterns in your image.
Let's write the corrected version of your code. Bear in mind that I will not give an optimized version. Let's get a basic algorithm working, and it'll be up to you on how you want to optimize this. As such, change your code to something like this, bearing in mind all of the stuff I talked about above. BTW, your function is not defined properly. You can't use spaces to define your function, as well as your variables. It will interpret each word in between spaces as variables or functions, and that's not what you want. Assuming your neighbourhood size is 3 x 3 and your image is grayscale, try something like this:
function [ ltp_upper, ltp_lower ] = LTP(im, t)
%// Get the dimensions
rows=size(im,1);
cols=size(im,2);
%// Reordering vector - Essentially for getting binary strings
reorder_vector = [8 7 4 1 2 3 6 9];
%// For the upper and lower LTP patterns
ltp_upper = zeros(size(im));
ltp_lower = zeros(size(im));
%// For each pixel in our image, ignoring the borders...
for row = 2 : rows - 1
for col = 2 : cols - 1
cen = im(row,col); %// Get centre
%// Get neighbourhood - cast to double for better precision
pixels = double(im(row-1:row+1,col-1:col+1));
%// Get ranges and determine LTP
out_LTP = zeros(3, 3);
low = cen - t;
high = cen + t;
out_LTP(pixels < low) = -1;
out_LTP(pixels > high) = 1;
out_LTP(pixels >= low & pixels <= high) = 0;
%// Get upper and lower patterns
upper = out_LTP;
upper(upper == -1) = 0;
upper = upper(reorder_vector);
lower = out_LTP;
lower(lower == 1) = 0;
lower(lower == -1) = 1;
lower = lower(reorder_vector);
%// Convert to a binary character string, then use bin2dec
%// to get the decimal representation
upper_bitstring = char(48 + upper);
ltp_upper(row,col) = bin2dec(upper_bitstring);
lower_bitstring = char(48 + lower);
ltp_lower(row,col) = bin2dec(lower_bitstring);
end
end
Let's go through this code slowly. First, I get the dimensions of the image so I can iterate over each pixel. Also, bear in mind that I'm assuming that the image is grayscale. Once I do this, I allocate space to store the upper and lower LTP patterns per pixel in our image as we will need to output this to the user. I have decided to ignore the border pixels where when we consider a pixel neighbourhood, if the window goes out of bounds, we ignore these locations.
Now, for each valid pixel that is within the valid borders of the image, we extract our pixel neighbourhood. I convert these to double precision to allow for negative differences, as well as for better precision. I then calculate the low and high ranges, then create a LTP pattern following the guidelines we talked about above.
Once I calculate the LTP pattern, I create two versions of the LTP pattern, upper and lower where any values of -1 for the upper pattern get mapped to 0 and 1 for the lower pattern. Also, for the lower pattern, any values that were 1 from the original window get mapped to 0. After, this, I extract out the bits in the order that I laid out - starting from the east, go counter-clockwise. That's the purpose of the reorder_vector as this will allow us to extract those exact locations. These locations will now become a 1D vector.
This 1D vector is important, as we now need to convert this vector into character string so that we can use bin2dec to convert the value into a decimal number. These numbers for the upper and lower LTPs are what are finally used for the output, and we place those in the corresponding positions of both output variables.
This code is untested, so it'll be up to you to debug this if it doesn't work to your specifications.
Good luck!