Find all numbers which are equal to the sum of the factorial of their digits - matlab

How can Find all numbers (e.g. 145= 1! + 4! + 5! = 1 + 24 + 120 = 145.)
which are equal to the sum of the factorial of their digits, by MATLAB?
I want to chop off digits, add the factorial of the digits together and compare it with the original number. If factorial summation be equal to original number, this numbers is on of the solution and must be keep. I can't code my idea, How can I code it? Is this true?
Thanks

The main reason that I post this answer is that I can't leave the use of eval in the previous answer without a decent alternative
Here is a small function to check this for any given (integer) n:
isFact = #(n) n==sum(factorial(int2str(n)-'0'));
Explanation:
int2str(n)-'0': "chop off digits"
sum(factorial(...)): "add the factorial of the digits together"
n==...: "compare it with the original number"
You can now plug it in a loop to find all the numbers between 1 to maxInt:
maxInt = 100000; % just for the example
solution = false(1,maxInt); % preallocating memory
for k = 1:maxInt
solution(k) = isFact(k);
end
find(solution) % find all the TRUE indices
The result:
ans =
1 2 145 40585
The loop above was written to be simple. If you look for further efficiency and flexibility (like not checking all the numbers between 1 to maxInt and checking array in any shape), you can change it to:
% generating a set of random numbers with no repetitions:
Vec2Check = unique(randi(1000,1,1000)); % you can change that to any array
for k = 1:numel(Vec2Check)
if isFact(Vec2Check(k))
Vec2Check(k) = Vec2Check(k)+0.1;
end
end
solution = Vec2Check(Vec2Check>round(Vec2Check))-0.1
The addition of 0.1 serves as a 'flag' that marks the numbers that isFact returns true for them. We then extract them by comparing the vector to it's rounded vertsion.
You can even go with a one-line solution:
solution = nonzeros(arrayfun(#(n) n.*(n==sum(factorial(int2str(n)-'0'))),Vec2Check))

The following snippet finds the numbers up to 1000 satisfying this condition.
numbers = [];
for i=1:1000
number_char = int2str(i);
sum = 0;
for j=1:length(number_char)
sum = sum+ factorial(eval(number_char(j)));
end
if (sum == i)
numbers(end+1) = i;
end
end
disp(numbers)
This should yield:
1 2 145
Note that if (log10(n)+1)*9! is less than n, then there is no number satisfying the condition larger than n.

Related

Count values from range in Matlab

I want to count the number of values in the array. I have a code which works:
Range = [1:10^3];% [1:10^6];
N = 10^2;% 10^8
Data = randi([Range(1),Range(end)],N,1);
Counts = nan(numel(Range),1);
for iRange = 1:numel(Range)
Counts(iRange) = sum(Data==Range(iRange));
end
Could you help me to make this code faster?
I feel that it should be via unique or hist, but I could not find a solution.
N = histcounts(Data,Range)
gives me 999 numbers instead of 1000.
As Ander Biguri stated at a comment, histcounts is what you seek.
The function counts the number of values of X (Data in your example), are found at every bin between two edges, where bins defined as such:
The value X(i) is in the kth bin if edges(k) ≤ X(i) < edges(k+1).
While the last bin also includes the right edges.
This means:
For N values, you need N+1 edges.
Each bin should start at the value you want it to include (1 between 1:2, 2 between 2:3, etc).
In your example:
Counts = histcounts(Data,Range(1):(Range(end)+1))';
I wanted to point out an issue with this code:
Counts = nan(numel(Range),1);
for iRange = 1:numel(Range)
Counts(iRange) = sum(Data==Range(iRange));
end
It shows a single loop, but == and sum work over all elements in the array, making this really expensive compared to a loop that doesn't do so, especially if N is large:
Counts = zeros(numel(Range),1);
for elem = Data(:).'
Counts(elem) = Counts(elem) + 1;
end

How to check my matrix if its divisible by 12

im new to matlab and i've run into a slight problem. I want to check my matrix that generated random number if they are divisible by 12. Then i want to list number of digit divisible by 12 and the total sum of those.
clc
clear
format compact
a=4
b=0
N=50+a
R=randi([100+a,159+b], 1, N) % generate random no. from 100+a to 159 on a matrix 1xN
s1=0
N1=0
for i = 1
for j= 1:N
if rem(R,12)==0
N1=N1+1;
s1=s1+R(i,j);
else
N1=N1+0;
s1=s1+0;
end
end
end
numberof1=N1
sum1=s1
Your code isn't working because your are calling rem(R, 12) (remainder of all elements) as opposed to the remainder of the specific element (rem(R(i,j), 12)).
The better approach though would be to remove the for loop and generate a logical matrix the size of R that is true when that number is divisible by 12 and false otherwise by passing the entire matrix to rem.
is_divisible_by_12 = rem(R, 12) == 0;
Then we can use this to compute the sum of these by using this logical array as an index into R
subset = R(is_divisible_by_12);
number = numel(subset);
s1 = sum(subset);

Random number generation - code not working as it should

So I have to generate a random number (called 'p' here) between 0 and 90 whose frequency distribution is a cosine function (i.e I should have more numbers between 0 and 45 than numbers between 45 and 90).
I am working on matlab
The code is as follows -
flag = 1;
while flag == 1
candidate = randi([0,90]);
if rand < cosd( candidate )
p = candidate;
flag = 2;
end
end
I am generating 20 such numbers but always I get most of the numbers towards the higher end (45-90).
From those 20 numbers, there is hardly 1-2 numbers < 45.
Is my code wrong?
EDIT: Okay, so I got the answer. I tried running the code separately as follows-
for i = 1:20
flag = 1;
while flag == 1
candidate = randi([0,90]);
if rand < cosd( candidate )
p = candidate;
flag = 2;
disp(p);
end
end
end
And I'm getting most of the values of p between 0 and 45. My original code had an external 'if' condition which was the reason for only accepting higher values of 'p'. I used a while loop and the number of iterations were much more than 20 to get 20 values of 'p'.
Here is my original code snippet -
while zz <=20
d = randi([0,359]);
flag = 1;
while flag == 1
c = randi([0,90]);
x = rand(1);
if x < cosd(c)
p = c;
flag = 2;
end
end
if 'external condition'
strike(zz) = d;
dip(zz) = p;
slip(zz) = round(i);
zz= zz+1;
end
end
If you just want to get answer, read the last line. But if you want to know that why that answer is right, read the explanation.
Assume that you have a distinct distribution function like this:
f(0)=1;
f(1.5)=10;
f(4)=9;
So the cumulative function is:
F(0)=1;
F(1.5)=11;
F(4)=20;
No we want to have a relative cumulative function, as F(4)=20 (4 is the last item), we divide cumulative function by 20. So it would be:
F'(0)=0.05
F'(1.5)=0.55
F'(4)=1.00
Now, we generate a random number between 0 and 1. Every time we generate a random number, we generate a value for F'(x) and if F'(x) does not have that value anywhere, we use nearest bigger number (like y) which for some x, F(x)=y. For my example, based on relative cumulative function:
If the random number was less than 0.05, our distribution-based random number is 1.5
If the random number was between 0.05 and 0.55, our distribution-based random number is 2,
If was more than 0.55, our distribution-based random number is 4
We should do a similar work with continuous distribution functions. The difference is that in continuous world, we use integral instead of cumulative function. So for your question, we have:
f(x)=cos(x) , 0<=x<=90
F(x)=sin(x)-sin(0)=sin(x) , 0<=x<=90
F'(x)=cos(x) , 0<=x<=90 (Because F(90)=1)
Now we generate a random number between 0 and 1 (like r). So we have:
F'(x)=r => sin(x)=r => x=arcsin(r)
Actually, you just need to generate a random number between 0 and 1 and calculate the arcsin of that.

A different method to check if an element is even in matlab?

This was the original question:
Write a script that asks the user for two positive numbers a and b and calculates the sum of the even numbers in the range [a,b]. The script should print a message with the range and the sum values as shown in the example below.
Enter the first number of the range: 3
Enter the last number of the range: 12
The sum of the even numbers in the range [3,12] is 40
I was able to solve it using the Rem function
a=input('Enter the first number of the range: ',d);
b=input('Enter the last number of the range: ',d);
m=0
For i=a:b;
If rem(i,2)=0
m=i+m;
End
End
fprintf('The sum of the even numbers in the range [%d,%d] is %d\n',a,b,m)
My question is, since I knew about the Rem function I was able to solve it. How does one do this without knowing the Rem function, and this brought up another question. What if they wanted me to list the prime numbers, what is the method of check in that case?
How about just
if ~mod(a,2)
m = sum(a:2:b)
else
m = sum(a+1:2:b)
end
In this case mod is only used to check only a. This is the only check that is needed
There are many ways to check if a number is even or not
here is one alternative:
round(number/2) == (number/2)
Sample 1
>> number
number =
81
>> ans
ans =
0
Sample 2
>> number
number =
92
>> ans
ans =
1
There is also an inbuilt function ( isprime ) for checking if a number is prime or not
Example from mathworks:
>> isprime([2 3 0 6 10])
ans =
1 1 0 0 0
For the sum of even numbers, you could use:
numbers = 2*(ceil(a/2):floor(b/2)); %// even numbers in the given range
result = sum(numbers);
To save operations, you can multiply by 2 only at the end:
result = 2*sum((ceil(a/2):floor(b/2)));
Or compute the result directly:
x = ceil(a/2);
y = floor(b/2);
result = (y+x)*(y-x+1);

project euler 23 MATLAB

I'm slowly working my way though problem 23 in project Euler but I;ve run into a snag. Problem #23 involves trying to find the sum of all numbers that cannot be creat by two abundant numbers.
First here's my code:
function [divisors] = SOEdivisors(num)
%SOEDIVISORS This function finds the proper divisors of a number using the sieve
%of eratosthenes
%check for primality
if isprime(num) == 1
divisors = [1];
%if not prime find divisors
else
divisors = [0 2:num/2]; %hard code a zero at one.
for i = 2:num/2
if divisors(i) %if divisors i ~= 0
%if the remainder is not zero it is not a divisor
if rem(num, divisors(i)) ~= 0
%remove that number and all its multiples from the list
divisors(i:i:fix(num/2)) = 0;
end
end
end
%add 1 back and remove all zeros
divisors(1) = 1;
divisors = divisors(divisors ~= 0);
end
end
This function finds abundant numbers
function [abundantvecfinal] = abundantnum(limitnum)
%ABUNDANTNUM creates a vector of abundant numbers up to a limit.
abundantvec = [];
%abundant number count
count = 1;
%test for abundance
for i = 1:limitnum
%find divisors
divisors = SOEdivisors(i);
%if sum of divisors is greater than number it is abundant, add it to
%vector
if i < sum(divisors)
abundantvec(count) = i;
count = count + 1;
end
end
abundantvecfinal = abundantvec;
end
And this is the main script
%This finds the sum of all numbers that cannot be written as the sum of two
%abundant numbers and under 28123
%get abundant numbers
abundant = abundantnum(28153);
%total non abundant numbers
total = 0;
%sums
sums = [];
%count moves through the newsums vector allowing for a new space for each
%new sum
count = 1;
%get complete list of possible sums under using abundant numbers under
%28123 then store them in a vector
for i = 1:length(abundant)
for x = 1:length(abundant)
%make sure it is not the same number being added to itself
if i ~= x
sums(count) = abundant(i) + abundant(x);
count = count + 1;
end
end
end
%setdiff function compares two vectors and removes all similar elements
total = sum(setdiff(1:28153, sums));
disp(total)
The first problem is it gives me the wrong answer. I know that I'm getting the correct proper divisors and the correct abundant numbers so the problem probably lies in the main script. And it seems as though it almost certainly lies in the creation of the abundant sums. I was hoping someone might be able to find an error I havent been able to.
Beyond that, the code is slow due to the multiple for loops, so I'm also looking for ways to do problems like this more efficiently.
Thanks!
Well, I don't have enough reputation to just comment. Why are you ruling out adding the same number to itself? The problem statement gives the example 12+12=24.
I also don't see a reason that x should ever be less than i. You don't need to sum the same two numbers twice.