Converting an array of doubles to a string
Converting "double" to "string"
matlab - convert from double to strings - Stack Overflow
double to string in a cell
Videos
I'm working with some data that lists the duration (time) of an experiment as, "1.6420e+04". The type given by class(Duration) is double. I'd like to convert this to a string that reads "1.6420e+04" but can't find a good way to do it. sprintf('%f',Duration) returns 16420.479075, num2str also gives the incorrect answer (though there is apparently a precision option that might be able to help which I can't figure out) and there doesn't seem to be any double2str. Does anyone know a way to accomplish this or how to convert this double into a more readable float?
One way to do this is to use sprintf to convert the array to a long string of digits. You can then reshape this string into the appropriate shape. Then you can use cellstr to convert each row of the reshaped string into a separate cell array element.
out = cellstr(reshape(sprintf('%d', A), [], size(A,2)));
Explanation
First convert the matrix into a long string of digits.
s = sprintf('%d', A)
%// 1234123411112222111111112222222211111111
Then we want to reshape this so that each row of numbers in the original is a row of numbers in the output
s = reshape(s, [], size(A,2))
%// 11121
%// 21121
%// 31121
%// 41121
%// 12121
%// 22121
%// 32121
%// 42121
Then we can use cellstr to convert each row of this into it's own cell array
out = cellstr(s);
%// '11121'
%// '21121'
%// '31121'
%// '41121'
%// '12121'
%// '22121'
%// '32121'
%// '42121'
A different approach
Another way that you could accomplish this is to treat each column of A as a place value (i.e. 10000's place, 1000's, place, 100's place, etc.) and convert each row to an integer knowing that. This can easily be done by multiplying each row with an array of 10^(N-1:-1:0) and summing the elements. This will yield a digit for each row that combines all of the columns. We can then use num2str to convert this to a cell array of strings.
%// Then convert each number to a string in a cell array
out = arrayfun(@num2str, A * (10.^(size(A, 2)-1:-1:0)).', 'uni', 0);
Or to shorten this even more, we can borrow a page out of @rayryeng's book and use sprintfc to convert this array of integers into a cell array of strings:
out = sprintfc('%d', A * (10.^(size(A, 2)-1:-1:0)).');
Benchmark
I was curious about the performance of the methods presented here and in @rayryeng's answer and Dev-iL's answer when you increase the number of rows. I wrote up a quick test script.
function tests()
% Test the number of rows between 100 and 10000
nRows = round(linspace(100, 10000, 100));
times1 = zeros(numel(nRows), 1);
times2 = zeros(numel(nRows), 1);
times3 = zeros(numel(nRows), 1);
times4 = zeros(numel(nRows), 1);
times5 = zeros(numel(nRows), 1);
%// Generate a random matrix of N x 5
getRandom = @(n)randi([0, 9], [n, 5]);
for k = 1:numel(nRows)
A = getRandom(nRows(k));
times1(k) = timeit(@()string_reshape_method(A));
A = getRandom(nRows(k));
times2(k) = timeit(@()base10_method(A));
A = getRandom(nRows(k));
times3(k) = timeit(@()sprintfc_method(A));
A = getRandom(nRows(k));
times4(k) = timeit(@()addition_method(A));
end
%// Plot the results
plot(nRows, cat(2, times1, times2, times3, times4)*1000);
legend({'String Reshape', 'Base-10 Conversion', 'sprintfc', 'addition of "0"'})
xlabel('Number of Rows in A')
ylabel('Execution Time (ms)');
end
function out = string_reshape_method(A)
out = cellstr(reshape(sprintf('%d', A), [], size(A,2)));
end
function out = base10_method(A)
out = sprintfc('%d', A * (10.^(size(A, 2)-1:-1:0)).');
end
function B = sprintfc_method(A)
B = sprintfc(repmat('%d', 1, size(A,2)), A);
end
function B = addition_method(A)
B = cellstr(char(A + '0'));
end
Here are the results.
My suggestion is this:
out = cellstr(char(A + '0'));
Basically what we do is add the ASCII value of 0 to your matrix then convert it to characters. I didn't benchmark it, but it should be comparably fast :)
Here are two simpler solutions to convert a single double value to a string and back without loss.
I want the string to be a human-readable representation of the number
Use num2str to obtain 17 decimal digits in string form, and str2double to convert back:
>> s = mat2str(x,17)
s =
'2.2204460492503131e-16'
>> y = str2double(s);
>> y==x
ans =
logical
1
Note that 17 digits are always enough to represent any IEEE double-precision floating-point number.
I want a more compact string representation of the number
Use matlab.net.base64encode to encode the 8 bytes of the number. Unfortunately you can only encode strings and integer arrays, so we type cast to some integer array (we use uint8 here, but uint64 would work too). We reverse the process to get the same double value back:
>> s = matlab.net.base64encode(typecast(x,'uint8'))
s =
'AAAAAAAAsDw='
>> y = typecast(matlab.net.base64decode(s),'double');
>> x==y
ans =
logical
1
Base64 encodes every 3 bytes in 4 characters, this is the most compact representation you can easily create. A more complex algorithm could likely convert into a smaller UTF-8-encoded string (which uses more than 6 bytes per displayable character).
Function f: from double real-valued scalar x to char vector str
str = num2str(typecast(x, 'uint8'));
str is built as a string containing 8 numbers, which correspond to the bytes in the internal representation of x. The function typecast extracts the bytes as a numerical vector, and num2str converts to a char vector with numbers separated by spaces.
Function g: from char vector str to double real-valued scalar y
y = typecast(uint8(str2double(strsplit(str))), 'double');
The char vector is split at spaces using strsplit. The result is a cell array of char vectors, each of which is then interpreted as a number by str2double, which produces a numerical vector. The numbers are cast to uint8 and then typecast interprets them as the internal representation of a double real-valued scalar.
Note that str2double(strsplit(str)) is preferred over the simpler str2num(str), because str2num internally calls eval, which is considered evil bad practice.
Example
>> format long
>> x = sqrt(pi)
x =
1.772453850905516
>> str = num2str(typecast(x, 'uint8'))
str =
'106 239 180 145 248 91 252 63'
>> y = typecast(uint8(str2double(strsplit(str))), 'double')
y =
1.772453850905516
>> x==y
ans =
logical
1
Hey,
I need to convert a few million strings to double, in order to process them further. If i look at the runtime I found out that the conversion itself is very slow, therefore i changed str2double with str2doubleq which helped, but not as much. Is there a faster way to performe this operation?