1

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.

Wolfie
  • 27,562
  • 7
  • 28
  • 55
joe
  • 13
  • 2

1 Answers1

0

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'))) 
    ... 
Community
  • 1
  • 1
Wolfie
  • 27,562
  • 7
  • 28
  • 55