precision of string conversion using string()

18 vues (au cours des 30 derniers jours)
Cristian Berceanu
Cristian Berceanu le 31 Oct 2023
Modifié(e) : Dyuman Joshi le 31 Oct 2023
I used to do numeric to string conversion using compose, but I recently found out how easy it is to use just string(a). Nevertheless, I came across some precision issues when using it. See below, why is "pi" being converted with different precision in the various cases below?
Regards,
Cristian
>> string([pi])
ans = "3.1416"
>> string([pi 1])
ans =
1×2 string array
"3.1416" "1"
>> string([pi 100])
ans =
1×2 string array
"3.14159" "100"
>> string([pi 127])
ans =
1×2 string array
"3.141593" "127"
>> string([pi 15000])
ans =
1×2 string array
"3.14159265" "15000"

Réponse acceptée

Rik
Rik le 31 Oct 2023
Let's first replicate what you show:
my_fun([],@string)
my_fun([pi])
ans = "3.1416"
my_fun([pi 1])
ans = 1×2 string array
"3.1416" "1"
my_fun([pi 100])
ans = 1×2 string array
"3.14159" "100"
my_fun([pi 127])
ans = 1×2 string array
"3.141593" "127"
my_fun([pi 15000])
ans = 1×2 string array
"3.14159265" "15000"
The answer seems to be that this is the standard behaviour for num2str. So this is not unique to string. It does make sense that the precision for pi is increased if you add more precision for the other values in the array.
my_fun([],@num2str)
my_fun([pi])
ans = '3.1416'
my_fun([pi 1])
ans = '3.1416 1'
my_fun([pi 100])
ans = '3.141593 100'
my_fun([pi 127])
ans = '3.141593 127'
my_fun([pi 15000])
ans = '3.14159265 15000'
function my_fun(data,set_fun)
persistent fun
if nargin==2,fun=set_fun;return,end
feval(fun,data)
end
  1 commentaire
Cristian Berceanu
Cristian Berceanu le 31 Oct 2023
I guess I am going back to compose then...

Connectez-vous pour commenter.

Plus de réponses (1)

Dyuman Joshi
Dyuman Joshi le 31 Oct 2023
Modifié(e) : Dyuman Joshi le 31 Oct 2023
From the documentation of string, subsection - Input arguments :- Input Type - Numeric array
"Output format and precision equivalent to using num2str. Use compose to specify more precise formatting.
If A is empty, [], the output is a 0-by-0 empty string array.
Use char to convert to ASCII or Unicode points."
For a numeric array, the behaviour of string() is equivalent to that of num2str().
Now, the documentation of num2str does not specify why the output is such when a precision is not provided. It just mentions - "The output format depends on the magnitudes of the original values."
The precision for each numeric value when converting to text via string (and equivalently num2str) is determined by various parameters. You can get more information about this by checking out the code for num2str().
type num2str.m
function s = num2str(x, f) %NUM2STR Convert numbers to character representation % T = NUM2STR(X) converts the matrix X into its character representation T % with about 4 digits and an exponent if required. This is useful for % labeling plots with the TITLE, XLABEL, YLABEL, and TEXT commands. % % T = NUM2STR(X,N) converts the matrix X into a character representation % with a maximum N digits of precision. The default number of digits is % based on the magnitude of the elements of X. % % T = NUM2STR(X,FORMAT) uses the format specifier FORMAT (see SPRINTF for % details). % % Example: % num2str(randn(2,2),3) produces a character representation such as % % ' 1.44 -0.755' % '0.325 1.37' % % Example: % num2str(pi,'%.2f') produces a character representation such as % % '3.14' % % See also INT2STR, SPRINTF, FPRINTF, MAT2STR, STRING. % Copyright 1984-2020 The MathWorks, Inc. %------------------------------------------------------------------------------ if nargin > 0 x = convertStringsToChars(x); end if nargin > 1 f = convertStringsToChars(f); end narginchk(1,2); if ischar(x) s = x; return; end if isempty(x) s = ''; return end if ~isnumeric(x) && ~islogical(x) error(message('MATLAB:num2str:nonNumericInput') ); end if isfloat(x) x = 0+x; % Remove negative zero end if issparse(x) x = full(x); end intFieldExtra = 1; maxFieldWidth = 12; floatWidthOffset = 4; forceWidth = 0; padColumnsWithSpace = true; % Compose sprintf format string of numeric array. if nargin < 2 || (isinteger(x) && isnumeric(f)) % To get the width of the elements in the output string widthCopy = x; % replace Inf and NaN with a number of equivalent length (3 digits) for width % calcultion if isfloat(x) widthCopy(~isfinite(widthCopy)) = 314; %This could be any 3 digit number end xmax = double(max(abs(widthCopy(:)))); if isequaln(x, fix(x)) && (isinteger(x) || eps(xmax) <= 1) if isreal(x) s = int2str(x); % Enhance the performance return; end d = min(maxFieldWidth, floor(log10(xmax)) + 1); forceWidth = d+intFieldExtra; f = '%d'; else % The precision is unspecified; the numeric array contains floating point % numbers. if xmax == 0 d = 1; else d = min(maxFieldWidth, max(1, floor(log10(xmax))+1))+floatWidthOffset; end [s, forceWidth, f] = handleNumericPrecision(x, d); if ~isempty(s) return; end end elseif isnumeric(f) f = round(real(f)); [s, forceWidth, f] = handleNumericPrecision(x, f); if ~isempty(s) return; end elseif ischar(f) % Precision is specified as an ANSI C print format string. % Explicit format strings should be explicitly padded padColumnsWithSpace = false; % Validate format string if ~contains(f,"%") error(message('MATLAB:num2str:fmtInvalid', f)); end else error(message('MATLAB:num2str:invalidSecondArgument')) end %------------------------------------------------------------------------------- % Print numeric array as a string image of itself. if isreal(x) [raw, isLeft] = cellPrintf(f, x, false); [m,n] = size(raw); cols = cell(1,n); widths = zeros(1,n); for j = 1:n if isLeft cols{j} = char(raw(:,j)); else cols{j} = strvrcat(raw(:,j)); end widths(j) = size(cols{j}, 2); end else forceWidth = 2*forceWidth + 2; raw = cellPrintf(f, real(x), false); imagRaw = cellPrintf(f, imag(x), true); [m,n] = size(raw); cols = cell(1,n); widths = zeros(1,n); for j = 1:n cols{j} = [strvrcat(raw(:,j)) char(imagRaw(:,j))]; widths(j) = size(cols{j}, 2); end end maxWidth = max([widths forceWidth]); padWidths = maxWidth - widths; padIndex = find(padWidths, 1); while ~isempty(padIndex) padWidth = padWidths(padIndex); padCols = (padWidths==padWidth); padWidths(padCols) = 0; spaceCols = char(ones(m,padWidth)*' '); cols(padCols) = strcat({spaceCols}, cols(padCols)); padIndex = find(padWidths, 1); end if padColumnsWithSpace spaceCols = char(ones(m,1)*' '); cols = strcat(cols, {spaceCols}); end s = strtrim([cols{:}]); end function s = strvrcat(c) s = strjust(char(c)); end function [cells, isLeft] = cellPrintf(f, x, b) try [cells, err, isLeft] = sprintfc(f, x, b); if ~isempty(err) warning(message('MATLAB:num2str:badConversion', err)); end catch e warning(e.identifier, '%s', e.message); cells = {''}; isLeft = false; end end function [s, forceWidth, f] = handleNumericPrecision(x, precision) if isreal(x) s = convertUsingRecycledSprintf(x, precision); forceWidth = 0; f = ''; else floatFieldExtra = 6; s = ''; forceWidth = precision+floatFieldExtra; f = sprintf('%%.%dg', precision); end end function s = convertUsingRecycledSprintf(x, d) floatFieldExtra = 7; f = sprintf('%%%.0f.%.0fg', d+floatFieldExtra, d); [m, n] = size(x); scell = cell(1,m); pads = logical([]); for i = 1:m scell{i} = sprintf(f,x(i,:)); if n > 1 && (min(x(i,:)) < 0) pads(regexp(scell{i}, '([^\sEe])-')) = true; end end s = char(scell{:}); pads = find(pads); if ~isempty(pads) pads = fliplr(pads); spacecol = char(ones(m,1)*' '); for pad = pads s = [s(:,1:pad) spacecol s(:,pad+1:end)]; end end s = strtrim(s); end

Catégories

En savoir plus sur Characters and Strings dans Help Center et File Exchange

Produits


Version

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by