I wonder how to sum digits for a multi-digit number in Matlab.
For example 1241= 1+2+4+1 = 8
String-based answer:
>> n = 1241;
>> sum(int2str(n)-48)
ans =
8
The number is first converted to a string representation using int2str, then the ASCII code for '0' (i.e. 48) is subtracted from the ASCII code for each element of the string, producing a numeric vector. This is then summed to get the result.
A = 35356536576821;
A = abs(A);
xp = ceil(log10(A)):-1:1;
while ~isscalar(xp)
A = sum(fix(mod(A,10.^xp)./10.^[xp(2:end) 0]));
xp = ceil(log10(A)):-1:1;
end
this is the numeric approach
This one is the solution is character approach:
A = '35356536576821';
A = char(regexp(A,'\d+','match'));
while ~isscalar(A)
A = num2str(sum(A - '0'));
end
Both, first take the absolute number (strip the minus) then: the numeric one counts with log10() how many digits a number has and through modulus and divisions extracts the digits which are summed, while the char approach convert to numeric digits with implicit conversion of - '0', sums and converts back to string again.
Another all-arithmetic approach:
n = 1241; %// input
s = 0; %// initiallize output
while n>0 %// while there is some digit left
s = s + mod(n-1,10)+1; %// sum rightmost digit
n = floor(n/10); %// remove that digit
end
Youcan use this code
sum(int2str(n)-48)
where n, is your input number.
Related
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.
Example: 6.321: I need it to be 6.322.
5.14875: I need it to be 5.14876.
How can I do this?
If you represent numbers as floating point or double precision floating point, this problem is a disaster.
If you can read in a number as a string (you mentioned get the number with the input command), you could do:
x = input('ENTER A NUMBER: ','s');
decimal_place = find(fliplr(x)=='.',1) - 1;
x_val = str2double(x);
if(~isempty(decimal_place))
y = x_val + 10 ^ -decimal_place;
else % if there is no decimal place, find first non-zero digit to get sigfig
warning('ambiguous number of significant digits');
first_nonzero_digit = find(fliplr(x)~='0',1);
if(~isempty(first_nonzero_digit))
y = x_val + 10 ^ (first_nonzero_digit - 1);
else
y = x_val + 1;
end
end
disp('your new number is');
disp(y);
Example test runs:
ENTER A NUMBER: 1.9
your new number is
2
ENTER A NUMBER: 3510
your new number is
3520
ENTER A NUMBER: 323.4374
your number is
323.4375
ENTER A NUMBER: 0
your number is
1
#AndrasDeak - I think you're right the first time. The hard part is not the rounding - it's defining the "last" decimal.
Since floating point numbers aren't exact, I can't think of a reliable way to find that "last" decimal place - in any language.
There is a very hacky way that comes to mind, though. You could "print" the number to a string, with 31 numbers after the decimal point, then working right from the dot, find the first place with 15 0s. (Since double precision numbers can only stably represent the first 14 decimal places and you get a 15th that varies, 31 decimal place will ALWAYS give you at least 15 0s after the last sig digit.)
>> a = 1.34568700030041234556
a =
1.3457
>> str = sprintf('%1.31', a)
str =
Empty string: 1-by-0
>> str = sprintf('%1.31f', a)
str =
1.3456870003004124000000000000000
>> idx = strfind(str, '000000000000000')
idx =
19
>> b = a*10^(idx(1)-3)
b =
1.3457e+16
>> sprintf('%10.20f', b)
ans =
13456870003004124.00000000000000000000
>> c = b+1
c =
1.3457e+16
>> sprintf('%10.20f', c)
ans =
13456870003004124.00000000000000000000
>> final = floor(c)/10^(idx(1)-3)
final =
1.3457
>> sprintf('%10.31f', final)
ans =
1.3456870003004124000000000000000
I think that's a relatively reliable implementation.
http://www.mathworks.com/matlabcentral/answers/142819-how-to-find-number-of-significant-figures-in-a-decimal-number
assuming your just trying to do regular rounding:
i'd use the round function built into matlab.
let's do your example above..
5.14875 has 5 decimal places and you want it to be converterd to 5.14876.
Lets assume you that the 6th decimal place was 9 (so your number is 5.148759)
%Step 1:changethe format so that your going to be able to see all of the
%decimal places
format long
%step2:now enter the original number
OriginalNumber=5.148755
%step 3 take the original number and round it to your new number
NewNumber=round(OriginalNumber,5)
this solution will not work if the 6th number (that you did not show) was a <5 because the computer will not know to round up
assuming your just trying to cut the numbers off...
You cannot do this in regular default matlab floating point numbers. To keep my explination simple I'll just state that without an explination. I'd do some review on the different ways matlab stores # (int vs floating point) on the matlab website. They have excellent documentation.
I have a vector, A=[2 2 4 5]. I want to convert A to a number. Answer should be 2245.
Example 2. B=[5,6,7,8,9]. Answer should be 56789.
Thanks.
PS. Thanks to all. Now I understand to convert the vector to a string and delete the space, and convert back to a number.
You could try this -
>> a = [2 3 10];
>> str2num(strrep(num2str(a), ' ', ''))
ans =
2310
Why does it work? Well, num2str ("number to string") converts the vector into its character representation
>> num2str(a)
ans =
2 3 10
which is almost what you want, except for the spaces between the numbers. So you call strrep ("string replace") to replace all the spaces (' ') with the empty string ('')
>> strrep('hi there', ' ', '')
ans =
hithere
and finally use str2num ("string to number") to convert the resulting string back into a number.
Take each number, convert it to a string and concatenate the results. Take this string and convert it back into a number. You can use num2str on the array, remove any white spaces that result from this conversion using ismember then convert the string back to a number with num2str:
C = [2 3 10];
strC = num2str(C);
strC(ismember(strC, ' ')) = [];
out = str2num(strC)
out =
2310
Alternatively, you can use strrep to replace all spaces with nothing after you run num2str, then convert back to a number:
C = [2 3 10];
strC = num2str(C);
strC = strrep(strC, ' ', '');
out = str2num(strC)
out =
2310
Tipping the hat to Chris Taylor, this can all be done in one line:
out = str2num(strrep(num2str(C), ' ', ''))
out =
2310
One more for academic purposes is to use regular expressions. Specifically, use regexprep on the converted string array that is output from num2str and replace all spaces with nothing:
C = [2 3 10];
strC = num2str(C);
out = str2num(regexprep(strC, '\s*', ''))
out =
2310
The pattern \s* searches for 0 or more white space characters. We find these and set them to nothing.
Thanks to #obchardon for a correction.
This uses only arithmetics (no strings). It works for numbers greater than 0. A can be a row or column vector.
A = [2 0 3 10];
x = cumsum(floor(log10(A.'+(A.'==0)))+1);
x = x(end)-x;
result = A(:).'*10.^x
which gives
result =
20310
If you want to string all of the digits together like they are the digits in a single integer you can convert the vector to a string, remove the spaces to smoosh the digits together, and then convert it back to a single number.
This way will handle an arbitrary number of digits in each vector element (assuming they are all real integers) rather than trying to multiply each element by the respective power of 10 and taking the sum.
Example code:
A = [2 44 12 6];
Astr = num2str(A);
Astr(strfind(Astr, ' ')) = [];
Anum = str2double(Astr);
This uses num2str without having to worry about whitespaces.
Apply num2str to every number using arrayfun, concatenate the resulting strings, convert back to number. Sadly it is quite a bit slower than the whitespace-deleting or numerical approach.
numStrings = arrayfun(#num2str,a,'uni',0);
out = str2num(cat(2,numStrings{:}))
out =
2310
I'm looking for a really quick method in MATLAB of searching for a specific digit within an integer, ideally in a given position. For example:
Simple case...
I want to look through an array of integers and return all those which contain the number 1 eg 1234, 4321, 6515, 847251737 etc
More complex case...
I want to loop through an array of integers and return all those which contain the number 1 in the third digit eg 6218473, 541846, 3115473 BUT 175846 would not be returned.
Any thoughts?
There's a few answers here already, I'll throw my try into the pot.
Conversion to string can be expensive, so if it can be avoided, it should be.
n = 1:100000; % sample numbers
m = 3; % digit to check
x = 1; % number to find
% Length of the numbers in digits
num_length = floor(log10(abs(n)))+1;
% digit (from the left) to check
num_place = num_length-m;
% get the digit
digit_in_place = mod(floor(abs(n)./(10.^num_place)),10);
found_number = n(digit_in_place==x);
By casting to strings, the trick to vectorising is just to make sure x is a column vector. x(:) guarantees this. Also you need to left-align the strings which is done with the format specifier '%-d' where - is for left-alignment and d is for integers:
s = num2str(x(:), '%-d');
ind = s(:,3)=='1'
and this also allows you to easily solve your first case:
ind = any(s=='1',2)
in either case to recover your original number just go:
x(ind)
One way of getting there is to cast your numbers as strings and then check if the 3rd position of that string is '1'. It works perfectly fine in a loop, but I am confident that there is also a vectorized solution:
numbers = [6218473, 541846, 3115473, 175846]'
returned_numbers = [];
for i = 1:length(numbers)
number = numbers(i);
y = sprintf('%d', number) %// cast to string
%// add number to list, if its third character is 11
if strcmp(y(3), '1')
returned_numbers = [returned_numbers, number];
end
end
% // it returns:
returned_numbers =
6218473 541846 3115473
Code
%// Input array
array1 = [-94341 1234 4321 6515 847251737 6218473 541846 3115473 175846]
N = numel(array1); %// number of elements in input array
digits_sep = num2str(array1(:))-'0'; %//' Seperate the digits into a matrix
%// Simple case
output1 = array1(any(digits_sep==1,2))
%// More complex case output
col_num = 3;
%// Get column numbers for each row of the digits matrix and thus
%// the actual linear index corresponding to 3rd digit for each input element
ind1 =sub2ind(size(digits_sep),1:N,...
size(digits_sep,2)-floor(log10(abs(array1))-col_num+1));
%// Select the third digits, check which ones have `1` and use them to logically
%// index into input array to get the output
output2 = array1(digits_sep(ind1)==1)
Code run -
array1 =
-94341 1234 4321 6515 847251737 6218473 541846 3115473 175846
output1 =
-94341 1234 4321 6515 847251737 6218473 541846 3115473 175846
output2 =
6515 6218473 541846 3115473
I am representing a chaotic number with 15 digits after decimal i.e format long in matlab and i want to extract 3 numbers each containing 5 digits from the chaotic number. i.e if chaotic no. is 0.d1d2...d15 then i want (d1..d5),(d6..d10) & (d11..d15). it is always rounding off.I have written the following code.
num=x(n);
a1=floor(num*10^5);
disp('a1');
disp(a1);
a2=floor(num*10^10-a1*10^5);
disp(a2);
num=floor(num*10^15);
a3=mod(num,100000);
disp('a3');
disp(a3);
and the output is
0.320446597556797
a1
32044
a2
65975
a3
56796
its showing a3 as 56796 but i want 56797.
please help!!!
The problem is, very likely, that each operation you do to extract a group of digits introduces a small error, which is reflected in the last digit.
An alternative approach that avoids this:
num = pi; %// for example
str = num2str(num,'%0.15f'); %// string representation with 15 decimal digits
str = str(find(str=='.')+1:end); %// keep only digits after decimal point
a = base2dec(reshape(str,5,[]).',10); %'// convert string parts into numbers
Try this approach using strings -
n = 0.320446597556797 %// Input decimal number
t1 = num2str(n,'%1.15f')
t2 = strfind(t1,'.')
a = str2num(reshape(t1(t2+1:end),5,[])') %// output as a single matrix
Thanks to #Luis for the reshape idea! Hope you won't mind Luis!
It is probably a rounding error but if you really want those specific values, simply cast to a string and then rip the string apart. Something simple like below
a = 0.320446597556797;
format longg
aStr = num2str(a,'%1.15f');
decimals = regexp(aStr,'\.','Split');
decimals = decimals{2};
a1 = str2double(decimals(1:5));
a2 = str2double(decimals(6:10));
a3 = str2double(decimals(11:15));