This question already has answers here:
Why is 24.0000 not equal to 24.0000 in MATLAB?
(6 answers)
Closed 5 years ago.
The following if statement is only working properly if my digitToFind variable is 5, otherwise it gets ignored.
if(digitToFind == R)
digitToFindFreq = digitToFindFreq + 1;
end
The program is meant to count the number of digits in a given integer, and find the frequency of one specific number chosen by the user.
Example: 123445; number of digits is 6, frequency of 4 is 2.
digitToFindFreq = 0;
numOfDigits = 0;
integerInput = input('Enter an integer: ');
while(integerInput ~= round(integerInput))
fprintf('Invalid input. Try again!\n');
integerInput = input('Enter an integer: ');
end
digitToFind = input('Enter a digit number to find (0 to 9): ');
while(digitToFind < 0 || digitToFind > 9 || digitToFind ~= round(digitToFind))
fprintf('Invalid input. Try again!\n');
digitToFind = input('Enter a digit number to find (0 to 9): ');
end
if(integerInput == 0 && digitToFind ~= 0)
numOfDigits = 1;
digitToFindFreq = 0;
elseif(integerInput == 0 && digitToFind == 0)
numOfDigits = 1;
digitToFindFreq = 1;
end
while(integerInput >= 1)
integerInput = integerInput/10;
X = integerInput - fix(integerInput);
R = 10*X;
if(digitToFind == R)
digitToFindFreq = digitToFindFreq + 1;
end
integerInput = integerInput - X;
numOfDigits = numOfDigits + 1;
end
fprintf('\nNumber of digits: %d, Digit to find frequency: %d\n',numOfDigits,digitToFindFreq);
I have never had an issue like this before. It must be something small that I am missing because otherwise the program works properly.
This is probably an issue with floating point numbers, when you are dividing and multiplying by 10, and subtracting remainders, your value is not remaining an integer. Therefore a direct == test may fail.
1.0000000000000001 == 1 % False
You should replace your test with this:
if(abs(digitToFind - R) < 0.1) % the digit must be close to digitToFind
digitToFindFreq = digitToFindFreq + 1;
end
Or use strings:
integerInput = num2str(integerInput);
digitToFind = num2str(digitToFind);
while length(integerInput) > 0
R = integerInput(end);
integerInput = integerInput(1:end-1);
if strcmp(digitToFind, R)
digitToFindFreq = digitToFindFreq + 1;
end
integerInput = integerInput - X;
numOfDigits = numOfDigits + 1;
end
Really though, use neither of those methods. You are not leveraging Matlab's in built indexing to do all of the hard work for you. I've re-written your whole code, so you can also see how to do your validation checks with strings instead of integers. Note with the below method, I've changed the input type so that num2str isn't needed and your integers can be much¹ bigger.
% include your error checking here, but based on strings
integerInput = '.';
digitToFind = '.';
% Check all characters in integerInput are digits 0-9, so integer
while ~(all(integerInput >= '0') && all(integerInput <= '9'))
% Include the 's' qualifier to convert input directly to string, allows
% for much longer integers than using num2str() later on
integerInput = input('Enter an integer: ', 's');
end
% Check digitToFind is 0-9, and only 1 character
while ~(all(digitToFind >= '0') && all(digitToFind <= '9')) || length(digitToFind) ~= 1
digitToFind = input('Enter a digit number to find (0 to 9): ', 's');
end
% use logical indexing to find vector of 1s and 0s in the positions where
% integerInput(i) = digitToFind. Then count the number of non-zero elements
% using nnz (in built function). No need for your edge-case 0 checks either.
numOfDigits = length(integerInput);
digitToFindFreq = nnz(integerInput == digitToFind);
¹ A note on maximum input sizes
intmax('uint64') = 18446744073709551615 is the largest (unsigned) integer Matlab can handle. Note that realmax = 1.7977e+308 is significantly larger! For your application, I would assume it's desirable to allow inputs greater than ~20 digits, so representing them as integers is going to have issues. This may be another reason you are having issues with your tests, as anything over the intmax limit will have to be stored as a floating point (real) number, not an integer!
By using the 's' flag with the input command, the input number isn't evaluated as an integer, and instead it's converted directly to a string. The string variable's maximum length is only dependent on your computer's memory so could be enormous! For instance, I can create a 900,000,000 element string (1.8 Gigabytes) before I run out of memory.
Edit:
In the above, to check for digits being in the range 0-9, I'm using the fact that their ASCII values are consecutive, as that's what's being compared. You could also use the in-built isstrprop
while ~(all(isstrprop(integerInput, 'digit')))
...
Related
I wrote some code to display the prime numbers between 2 and a user-chosen number, following the pseudocode on wikipedia. I am not sure why this does not work, as I have the increments correct following Erastothenes' Sieve. Please help me.
I have tried changing the bounds but this did not work.
There are no errors, but it returns the wrong output. If I enter 10, it returns 2, 3, 4, 5, 6, 7, 8, 9, 10.
n=input("Enter an upper limit: ");
nums= 2:n;
p=2;
for i = p:sqrt(n)
for j = (i^2):i:sqrt(n)
nums(j) = 0;
end
end
for k = 1:n-1
if nums(k) ~= 0
disp(nums(k))
end
end
You can use the primes function in MATLAB for this
N = 10; % upper limit
p = primes(N); % List of all primes up to (and including) N
With one step less automation, you could use another in-built isprime
p = 1:N; % List of all numbers up to N
p( ~isprime( p ) ) = []; % Remove non-primes
Finally without using built-ins, we can address your code!
I assume you're referring to this pseudocode for the Sieve of Eratosthenes on Wikipedia.
Input: an integer n > 1.
Let A be an array of Boolean values, indexed by integers 2 to n,
initially all set to true.
for i = 2, 3, 4, ..., not exceeding √n:
if A[i] is true:
for j = i2, i2+i, i2+2i, i2+3i, ..., not exceeding n:
A[j] := false.
Output: all i such that A[i] is true.
I'll follow it step by step, pointing out differences to your code:
n = 10;
A = [false; true(n-1,1)]; % array of true Booleans, first element (1) is not prime
% But I've included a first element to make indexing easier.
% In your code, you were using index 'i' which was incorrect, as your array started at 2.
% Two options: (1) take my approach and pad the array
% (2) take your approach and using indices i-1 and j-1
for ii = 2:sqrt(n)
if A(ii) == true % YOU WERE MISSING THIS STEP!
for jj = ii^2:ii:n % YOU ONLY LOOPED UNTIL SQRT(n)!
A(jj) = false;
end
end
end
p = find(A);
disp(p)
This outputs the expected values.
Note that, at the end of the manual looping method, A is equivalent to isprime(1:n), mirroring my earlier suggestions.
There is two mistakes in your code:
The multiple should be check until n and not sqrt(n)
Since your nums vector start with 2 and not 1, if you want to
access the right value you need to use nums(j-1) = 0
So:
n=100
nums= 2:n;
p=2;
for i = p:sqrt(n)
for j = (i^2):i:n
nums(j-1) = 0;
end
end
for k = 1:n-1
if nums(k) ~= 0
disp(nums(k))
end
end
Noticed that you can skip one for loop using a modulo, it's probably not faster than the previous solution since this code create a logical index that include each prime that already been found.
n = 100
nums= 2:n;
for i = 2:sqrt(n)
nums(mod(nums,i)==0 & nums != i) = [];
end
nums.'
I simply delete the value in nums that can be divided by x but not x.
I am sending a matrix to my function modifikuj, where I want to replace the elements of the matrix with:
1 if element is a prime number
0 if element is a composite number
0.5 if element is 1
I dont understand why it is not working. I just started with MATLAB, and I created this function:
function B = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j))
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
With
A = [1,2;3,4];
D = modifikuj(A);
D should be:
D=[0.5, 1; 1 0];
In MATLAB you'll find you can often avoid loops, and there's plenty of built in functions to ease your path. Unless this is a coding exercise where you have to use a prescribed method, I'd do the following one-liner to get your desired result:
D = isprime( A ) + 0.5*( A == 1 );
This relies on two simple tests:
isprime( A ) % 1 if prime, 0 if not prime
A == 1 % 1 if == 1, 0 otherwise
Multiplying the 2nd test by 0.5 gives your desired condition for when the value is 1, since it will also return 0 for the isprime test.
You are not returning anything from the function. The return value is supposed to be 'B' according to your code but this is not set. Change it to A.
You are looping k until A(i,j) which is always divisible by itself, loop to A(i,j)-1
With the code below I get [0.5,1;1,0].
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j)-1)
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
In addition to #EuanSmith's answer. You can also use the in built matlab function in order to determine if a number is prime or not.
The following code will give you the desired output:
A = [1,2;3,4];
A(A==1) = 0.5; %replace 1 number with 0.5
A(isprime(A)) = 1; %replace prime number with 1
A(~ismember(A,[0.5,1])) = 0; %replace composite number with 0
I've made the assumption that the matrice contains only integer.
If you only want to learn, you can also preserve the for loop with some improvement since the function mod can take more than 1 divisor as input:
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
k = A(i,j);
if (k == 1)
A(i,j) = 0.5;
else
if all(mod(k,2:k-1)) %check each modulo at the same time.
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
And you can still improve the prime detection:
2 is the only even number to test.
number bigger than A(i,j)/2 are useless
so instead of all(mod(k,2:k-1)) you can use all(mod(k,[2,3:2:k/2]))
Note also that the function isprime is a way more efficient primality test since it use the probabilistic Miller-Rabin algorithme.
q = 2;
k= 2^q;
x1 = [0.0975000000000000, 0.980987500000000, -0.924672950312500, -0.710040130079246];
for i = 1 : length(x1)
[idx_centers,location] = kmeans(x1',q);
end
temp = idx_centers;
for i = 1 : length(x1)
if temp(i)== 2
idx_centers(i) = 0;
end
BinaryCode_KMeans(i) = idx_centers(i); % output is say [0,0,1,1];
end
strng = num2str(BinaryCode_KMeans);
DecX = bin2dec(strng);
In the above code snippet, I want to express the binary string to its decimal equivalent where the binary string is obtained from kmeans clustering. The decimal equivalent should either be 1,2,3, or 4 i.e., k = 2^q when q=2.
But sometimes after conversion, the decimal equivalent is 12 because for a 4 bit binary code we get decimal numbers in 1 to 16 or 0 -- 15. the number of elements in x1 can vary and can be less than or greater than k. What should I do so that I can always get the decimal equivalent of the binary code within k for any value of q?
First of, there is no need to run kmeans multiple times, it will calculate the cluster centers using a single run. Note that, the code below tries to find a mapping between the clustering results and n the number of samples. There are three ways in the code below to encode this information.
clear
clc
q = 2;
k= 2^q;
n = 4;
x1 = rand(n,1);
fprintf('x1 = [ '); fprintf('%d ', x1); fprintf(']\n');
[idx_centers, location] = kmeans(x1, q);
fprintf('idx_centers = [ '); fprintf('%d ', idx_centers); fprintf(']\n');
for i = 1:q
idx_centers(idx_centers == i) = i-1;
end
fprintf('idx_centers = [ '); fprintf('%d ', idx_centers); fprintf(']\n');
string = num2str(idx_centers');
% Original decimal value
DecX = bin2dec(string);
fprintf('0 to (2^n) - 1: %d\n', DecX);
% Reduced space decimal value
% Ignoring the 0/1 order as [ 1 1 0 0 ]
% would be the same as [ 0 0 1 1 ]
if DecX >= (2^n)/2
complement = bitget(bitcmp(int64(DecX)),n:-1:1);
DecX = bin2dec(num2str(complement));
end
fprintf('0 to ((2^n)/2) - 1: %d\n', DecX);
% Minimal Decimal value based on the number of samples
% in the 0's cluster which is in the range of 0 to n-1
fprintf('0 to n - 1: %d\n', numel(find(idx_centers == 0)));
Hint: If you change the q to more than 2, the code will not work because bin2dec only accepts zeros and ones. In case of having more than 2 clusters, you need to elaborate the code and use multidimensional arrays to store the pairwise clustering results.
I am trying out the questions in programming assignment of Coursera course on Matlab programming as an exercise. This is for my self-study.
Question:
Write a function called classify that takes one input argument x. That
argument will have no more than two dimensions. If x is an empty
matrix, the function returns -1. If x is a scalar, it returns 0. If x
is a vector, it returns 1. Finally, if x is none of these, it returns
2. Do not use the built-in functions isempty, isscalar, or isvector.
My code snippet:
function num = classify(x)
num = -1;
if(x == 3.14159265358979)
num = 0;
elseif(size(x, 2) == 3)
num = -1;
end
end
I got the below result on Matlab.
Problem 4 (classify):
Feedback: Your function performed correctly for argument(s) []
Feedback: Your function performed correctly for argument(s) zeros(1,0)
Feedback: Your function performed correctly for argument(s) zeros(0,4)
Feedback: Your function performed correctly for argument(s) 3.14159265358979
Feedback: Your function made an error for argument(s) [1 2 3]
Am I doing something wrong for arguments [1 2 3]?
If all you want is the code, I'll provide you with the answer, but I suggest you sit down and try to understand how and why this codes solves the problem, I'm guessing you want to learn something from it. Well, here's the code:
function [num] = classify(x)
if numel(x) == 0
num = -1;
return
end
num = sum(size(x) > 1);
end
You can most easily check if x is empty or a scalar by counting the number of elements (i.e. use the numel function). Then to determine if it is a vector or a higher dimensional matrix you need to check if the number of dimensions is less than 3 (this is because ndims returns 2 for both 1D and 2D matrices) and also verify that at least one of the first two dimensions has a size of 1:
function num = classify(x)
n = numel(x);
if n < 2
num = n-1;
else
if ndims(x) < 3 && any(size(x) == 1)
num = 1;
else
num = 2;
end
end
end
You should aim to write a generic function, your function would not work for example for any scalar input than pi.
Use the size function to determine the dimensions of the input, for example:
>> size([])
ans = 0 0
>> size(5)
ans = 1 1
>> size([5 6 7])
ans = 1 3
>> size([5;6;7])
ans = 3 1
Based on this, your function could looke like this:
function [num] = classify(x)
s = size(x);
if s == [0 0]
num = -1;
elseif s == [1 1]
num = 0;
elseif sort(s) == [1 3]
num = 1;
else
num = 2;
end
end
Yes, you tring to compare an array with a float.
It allows to do that (programaticalyl wrong) thing for [] because the array is empty
And for zeros, because the array is empty again: in the first case 0 columns, and in the second 0 rows
function i=classify(x)
[m, n]=size(x);
if n==1 && m==1
i=0;
elseif (m==0 && n==0)|| (m>=1 && n==0) || (m==0 && n>=1)
i=-1;
elseif (n>=1 && m==1) || (n==1 && m>=1)
i=1;
else i=2;
end
function y=classify(x)
[a b]=size(x);
%check for empty matrix
% Do not forget that an empty matrix can be size a x 0 or 0x a, where a can be
% arbitrary number
if (a>0)&&(b==0)||(a==0)&&(b>0)||(a==0)&&(b==0)
y=(-1);
%check for scalar
elseif (a==1)&&(b==1)
y=0;
%check for vector
elseif (a>=1)&&(b==1)||(a==1)&&(b>=1)
y=1;
%other case
else
y=2;
end
This question already has answers here:
Series of consecutive numbers (different lengths)
(3 answers)
Closed 8 years ago.
Grid_outage(:,1) = 1;
Grid_outage(:,2) = 1;
Grid_outage(:,3) = 1;
Grid_outage(:,4) = 0;
Grid_outage(:,5) = 0;
Grid_outage(:,6) = 0;
Grid_outage(:,7) = 0;
Grid_outage(:,8) = 0;
Grid_outage(:,9) = 0;
Grid_outage(:,10) = 0;
Grid_outage(:,11) = 0;
Grid_outage(:,12) = 1;
Grid_outage(:,13) = 0;
Grid_outage(:,14) = 1;
Grid_outage(:,15) = 0;
Grid_outage(:,16) = 0;
Grid_outage(:,17) = 1;
Grid_outage(:,18) = 0;
Grid_outage(:,19) = 1;
Grid_outage(:,20) = 0;
Grid_outage(:,21) = 0;
Grid_outage(:,22) = 0;
Grid_outage(:,23) = 1;
Grid_outage(:,24) = 0;
I would like to count the maximum number of Zeros that occur in a sequence, for e.g. I would like that above result be 8 which shows the maximum number of zeros that occur together, rather than the total number of zeros which is 16.
How do I code that in matlab
For the purpose of transparency a very simple algoritm.
Assume you can put your sequence in a vector X:
% Create X containing some zeros.
X = round(rand(30,1));
% Use a counter to count the number of sequential zeros.
count = 0;
% Use a variable to keep the maximum.
max_count = 0;
% Loop over every element
for ii=1:length(X);
% If a zero is encountered increase the counter
if(X(ii)==0)
count=count+1;
% If no zero is encountered check if the number of zeros in the last sequence was largest.
elseif count>max_count
max_count=count;
count=0;
% Else just reset the counter
else
count=0;
end
end
% Check if the last number of the vector exceeded the largest sequence.
if(count>max_count)
max_count=count;
end
EDIT: Dan's solution is more efficient starting from approximately ~200 elements.
max(diff(find(diff(Grid_outage))))
Find where a sequence of consecutive numbers changes using diff
Get the actual index numbers of where this happens using find
Use diff again to count the number of elements between each "transition"
Finally call max to get the largest sequence of consecutive numbers.
Note that you might have trouble if the largest sequence occurs at the edges, in this case I suggest that you first prepend and append an inverted bit to your matrix like this: [1-Grid_outage(1), Grid_outage, 1-Grid_outage(end)];
In order to find how many times the parameter x occurs together in a sequence, you can use:
if a(:) == x
result = length(a); % Whole vector has the x parameter
else
result = max(find(a~=x,1,'first') - 1, length(a) - find(a~=x,1,'last')); % Maximum difference in the edge
if ~isempty(max(diff(find(a~=x))) - 1)
if isempty(result)
result = max(diff(find(a~=x))) - 1; % Maximum difference in the body
elseif result < max(diff(find(a~=x))) - 1
result = max(diff(find(a~=x))) - 1; % Maximum difference in the body
end;
end;
end;