Undocumented Matlab
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT

sprintfc – undocumented helper function

November 27, 2013 5 Comments

Every now and then I discover a useful built-in Matlab function, often by bumping into them within the m-code of standard functions. Such was the case, for example, of the ismembc function, that I described here back in 2009, and the dtstr2dtnummx function that I described in 2011. Today I describe another such function, sprintfc, based on a tip I received from Dirk Engel.

  • The requirement
  • The standard solutions
  • sprintfc
  • London training course – Feb/Mar 2014

The requirement

The use-case of generating a cell-array of formatted strings is often encountered. Unfortunately, the standard sprintf function generates a single string, rather than a cell-array of strings. So, for example,

>> data = pi * (0:.5:2)
data =
         0    1.5708    3.1416    4.7124    6.2832
>> sprintf('%.3f  ',data)
ans =
0.000  1.571  3.142  4.712  6.283

>> data = pi * (0:.5:2) data = 0 1.5708 3.1416 4.7124 6.2832 >> sprintf('%.3f ',data) ans = 0.000 1.571 3.142 4.712 6.283

This is nice, but not exactly what we need, which is a cell array that looks like this:

>> c  % c is a 1x5 cell array
c =
    '0.000'    '1.571'    '3.142'    '4.712'    '6.283'

>> c % c is a 1x5 cell array c = '0.000' '1.571' '3.142' '4.712' '6.283'

The standard solutions

There are several standard solution for getting the required cell array. A simple for-loop is one of the fastest of these, due to JIT optimizations in recent Matlab releases. Some of the other alternatives may seem very strange, but they perform faster than the simpler variants. Note that the following code should be run within a testing function, to remove extraneous influences on the timing (JIT compilation etc.):

% 1) Simple for-loop with sprintf
tic
for idx = 1 : 1000
    c = {};  %initialize
    % note: reallocations are not really a factor here, so don't bother preallocating
    for dataElement = data
        c{end+1} = sprintf('%.3f',dataElement);
    end
end
toc
% Elapsed time is 0.076002 seconds.
% 2) Using arrayfun + num2str
tic
for idx = 1 : 1000
    c = arrayfun(@(c) num2str(c,'%.3f'), data, 'uniform',false);
end
toc
% Elapsed time is 0.557993 seconds.
% 3) Using cellfun + num2str + num2cell
tic
for idx = 1 : 1000
    c = cellfun(@(c) num2str(c,'%.3f'), num2cell(data), 'uniform',false);
end
toc
% Elapsed time is 0.566924 seconds.
% 4) Using num2cell + num2str
tic
for idx = 1 : 1000
    c = num2cell(num2str(data','%.3f'),2)';
end
toc
% Elapsed time is 0.173026 seconds.
% 5) Using cellstr + num2str
tic
for idx = 1 : 1000
    c = reshape(cellstr(num2str(data(:),'%.3f')),size(data));
end
toc
% Elapsed time is 0.175769 seconds.
% 6) Using num2cell + num2str (after Urs Schwartz & Jiro Doke)
tic
for idx = 1 : 1000
    c = reshape(num2cell(num2str(data(:),'%.3f'),2),size(data));
end
toc
% Elapsed time is 0.170247 seconds.
% 7) Using strread + sprintf
tic
for idx = 1 : 1000
    c = reshape(strread(sprintf(['%.3f','$'], data),'%s', 'delimiter','$'),size(data));
end
toc
% Elapsed time is 0.059457 seconds.

% 1) Simple for-loop with sprintf tic for idx = 1 : 1000 c = {}; %initialize % note: reallocations are not really a factor here, so don't bother preallocating for dataElement = data c{end+1} = sprintf('%.3f',dataElement); end end toc % Elapsed time is 0.076002 seconds. % 2) Using arrayfun + num2str tic for idx = 1 : 1000 c = arrayfun(@(c) num2str(c,'%.3f'), data, 'uniform',false); end toc % Elapsed time is 0.557993 seconds. % 3) Using cellfun + num2str + num2cell tic for idx = 1 : 1000 c = cellfun(@(c) num2str(c,'%.3f'), num2cell(data), 'uniform',false); end toc % Elapsed time is 0.566924 seconds. % 4) Using num2cell + num2str tic for idx = 1 : 1000 c = num2cell(num2str(data','%.3f'),2)'; end toc % Elapsed time is 0.173026 seconds. % 5) Using cellstr + num2str tic for idx = 1 : 1000 c = reshape(cellstr(num2str(data(:),'%.3f')),size(data)); end toc % Elapsed time is 0.175769 seconds. % 6) Using num2cell + num2str (after Urs Schwartz & Jiro Doke) tic for idx = 1 : 1000 c = reshape(num2cell(num2str(data(:),'%.3f'),2),size(data)); end toc % Elapsed time is 0.170247 seconds. % 7) Using strread + sprintf tic for idx = 1 : 1000 c = reshape(strread(sprintf(['%.3f','$'], data),'%s', 'delimiter','$'),size(data)); end toc % Elapsed time is 0.059457 seconds.

There are also some File Exchange contributions that do a similar thing, including num2cellstr or mtx2charcell, which basically implement the last two variants.

sprintfc

It turns out that the standard num2str function uses an undocumented built-in function sprintfc that already does this for us in one fell swoop – this is both the simplest and the fastest solution:

% 8) fastest and simplest - sprintfc
tic
for idx = 1 : 1000
    c = sprintfc('%.3f',data);
end
toc
% Elapsed time is 0.015714 seconds.

% 8) fastest and simplest - sprintfc tic for idx = 1 : 1000 c = sprintfc('%.3f',data); end toc % Elapsed time is 0.015714 seconds.

This is a 35x speedup compared to arrayfun/cellfun, 5x speedup compared to the JIT-optimized for-loop, and 4x speedup compared to the fastest other variant. Useful indeed.
The syntax of the sprintfc function can be seen in the num2str.m function:

[cells, errorMsg, isLeft] = sprintfc(format, data, isImaginary);

[cells, errorMsg, isLeft] = sprintfc(format, data, isImaginary);

where isImaginary is an optional flag (default=false) indicating that data should be formatted as imaginary values with the specified magnitude:

>> data = pi * (-1:.5:1)
data =
   -3.1416   -1.5708         0    1.5708    3.1416
>> sprintfc('%.3f', data, false)
ans =
    '-3.142'    '-1.571'    '0.000'    '1.571'    '3.142'
>> sprintfc('%.3f', data, true)
ans =
    '-3.142i'    '-1.571i'    '+0.000i'    '+1.571i'    '+3.142i'

>> data = pi * (-1:.5:1) data = -3.1416 -1.5708 0 1.5708 3.1416 >> sprintfc('%.3f', data, false) ans = '-3.142' '-1.571' '0.000' '1.571' '3.142' >> sprintfc('%.3f', data, true) ans = '-3.142i' '-1.571i' '+0.000i' '+1.571i' '+3.142i'

The second returned argument is an errorMsg string that is returned when sprintfc fails, typically due to an invalid format:

>> [c,errorMsg] = sprintfc('%r', data)
c =
    {''}
errorMsg =
Invalid format.

>> [c,errorMsg] = sprintfc('%r', data) c = {''} errorMsg = Invalid format.

The third returned value, isLeft, is apparently used to indicate whether the output cell-string is left-justified; namely, if the ‘-‘ flag is used within the format (thanks Yaroslav!). For example,

>> [cells, ~, isLeft] = sprintfc('%-8.5g', sqrt(2), false)
cells =
    '1.4142  '
isLeft =
    1
>> [cells, ~, isLeft] = sprintfc('%8.5g', sqrt(2), false)
cells =
    '  1.4142'
isLeft =
    0

>> [cells, ~, isLeft] = sprintfc('%-8.5g', sqrt(2), false) cells = '1.4142 ' isLeft = 1 >> [cells, ~, isLeft] = sprintfc('%8.5g', sqrt(2), false) cells = ' 1.4142' isLeft = 0

sprintfc has apparently remained in its current stable state since it was first introduced in the last decade (sometime between Matlab release 7.1 [in 2005] and R2008a). I do not know why MathWorks chose to keep sprintfc as an internal undocumented and unsupported function, despite its obvious usefulness.
If anyone finds any other similar useful built-ins, please do let me know.
Addendum: Starting in R2016b, the main functionality of sprintfc (excluding sprintfc‘s 3rd [isImaginary] input flag, and its 2nd/3rd output args [errorMsg and isLeft]) is included in the new fully-documented/supported function compose.

London training course – Feb/Mar 2014

I am planning a week of advanced Matlab training workshops/seminars in London in Feb/Mar 2014. I plan two separate courses:

  • Advanced Matlab Programming – 2 days, including best practices, preparing professional reports and performance tuning. US$ 999 until Jan 19, 2014; US$ 1199 for later registrations.
  • Advanced Matlab Visualization & GUI – 3 days, including advanced visualization and GUI techniques. US$ 1499 until Jan 19, 2014; US$ 1799 for later registrations.

This is a unique opportunity to enhance your Matlab skills in a few days, at an affordable cost, by an established expert. This training is not provided anywhere else. If you have a specific topic that you would like me to discuss, then I would be happy to do it. In other words, I can customize the training to your specific needs, within the provided framework. More details on my training can be found here.
If you are interested in the London courses or a private dedicated course, please Email me (altmany at gmail dot com) for details.
Happy Hanukkah/Thanksgiving everyone 🙂

Related posts:

  1. ismembc – undocumented helper function – Matlab has several undocumented internal helper functions that can be useful on their own in some cases. This post presents the ismembc function....
  2. Undocumented feature() function – Matlab's undocumented feature function enables access to some internal experimental features...
  3. tic / toc – undocumented option – Matlab's built-in tic/toc functions have an undocumented option enabling multiple nested clockings...
  4. cellfun – undocumented performance boost – Matlab's built-in cellfun function has an undocumented option to significantly improve performance in some cases....
  5. Function call timeline profiling – A new utility enables to interactively explore Matlab function call timeline profiling. ...
  6. Function definition meta-info – There are multiple ways to retrieve meta-info about functions in Matlab. ...
Performance Pure Matlab Undocumented function
Print Print
« Previous
Next »
5 Responses
  1. Yaroslav Don November 28, 2013 at 01:47 Reply

    Yair hi,
    After a short inspection I’ve come to the following conclusion: the third variable, isLeft, is used to indicate whether the output cell-string is left-justified; namely, if the '-' flag is used within the format. For example,

    >> [cells, ~, isLeft] = sprintfc('%-8.5g', sqrt(2), false)
    cells = 
        '1.4142  '
    isLeft =
        1

    >> [cells, ~, isLeft] = sprintfc('%-8.5g', sqrt(2), false) cells = '1.4142 ' isLeft = 1

    however,

    >> [cells, ~, isLeft] = sprintfc('%8.5g', sqrt(2), false)
    cells = 
        '  1.4142'
    isLeft =
        0

    >> [cells, ~, isLeft] = sprintfc('%8.5g', sqrt(2), false) cells = ' 1.4142' isLeft = 0

    Sincerely, Yaroslav

    • Yair Altman November 28, 2013 at 01:59 Reply

      @Yaroslav – ah! makes sense, also correlates with the num2str.m code. I’ve updated the main text accordingly. Thanks 🙂

  2. Matteo November 28, 2013 at 10:18 Reply

    Hi Yair

    I tried to figure out how to do this, and with higher dimension cell arrays, when I was still a Matlab newbie. I was obviously ahead of myself, but with a ton of reading, testing, and asking around, I managed. But if I needed to do that again it is good to know about this function. Great tip, nice post. Thanks

  3. Class object creation performance | Undocumented Matlab December 11, 2013 at 09:57 Reply

    […] Matlab application's performance and your Matlab programming skills in general, join my upcoming Advanced Matlab Programming course in London, March 2014 – an intensive 2 day course on best practices, preparing professional […]

  4. How do I make a column vector into an array of strings? - DexPage July 1, 2015 at 20:18 Reply

    […] you can use undocumented built-in function sprintfc to convert a numeric array to a cell array of strings like so […]

Leave a Reply
HTML tags such as <b> or <i> are accepted.
Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">
a = magic(3);
disp(sum(a))
</pre>
I reserve the right to edit/delete comments (read the site policies).
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.

Click here to cancel reply.

Useful links
  •  Email Yair Altman
  •  Subscribe to new posts (email)
  •  Subscribe to new posts (feed)
  •  Subscribe to new posts (reader)
  •  Subscribe to comments (feed)
 
Accelerating MATLAB Performance book
Recent Posts

Speeding-up builtin Matlab functions – part 3

Improving graphics interactivity

Interesting Matlab puzzle – analysis

Interesting Matlab puzzle

Undocumented plot marker types

Matlab toolstrip – part 9 (popup figures)

Matlab toolstrip – part 8 (galleries)

Matlab toolstrip – part 7 (selection controls)

Matlab toolstrip – part 6 (complex controls)

Matlab toolstrip – part 5 (icons)

Matlab toolstrip – part 4 (control customization)

Reverting axes controls in figure toolbar

Matlab toolstrip – part 3 (basic customization)

Matlab toolstrip – part 2 (ToolGroup App)

Matlab toolstrip – part 1

Categories
  • Desktop (45)
  • Figure window (59)
  • Guest bloggers (65)
  • GUI (165)
  • Handle graphics (84)
  • Hidden property (42)
  • Icons (15)
  • Java (174)
  • Listeners (22)
  • Memory (16)
  • Mex (13)
  • Presumed future risk (394)
    • High risk of breaking in future versions (100)
    • Low risk of breaking in future versions (160)
    • Medium risk of breaking in future versions (136)
  • Public presentation (6)
  • Semi-documented feature (10)
  • Semi-documented function (35)
  • Stock Matlab function (140)
  • Toolbox (10)
  • UI controls (52)
  • Uncategorized (13)
  • Undocumented feature (217)
  • Undocumented function (37)
Tags
ActiveX (6) AppDesigner (9) Callbacks (31) Compiler (10) Desktop (38) Donn Shull (10) Editor (8) Figure (19) FindJObj (27) GUI (141) GUIDE (8) Handle graphics (78) HG2 (34) Hidden property (51) HTML (26) Icons (9) Internal component (39) Java (178) JavaFrame (20) JIDE (19) JMI (8) Listener (17) Malcolm Lidierth (8) MCOS (11) Memory (13) Menubar (9) Mex (14) Optical illusion (11) Performance (78) Profiler (9) Pure Matlab (187) schema (7) schema.class (8) schema.prop (18) Semi-documented feature (6) Semi-documented function (33) Toolbar (14) Toolstrip (13) uicontrol (37) uifigure (8) UIInspect (12) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
  • Marcel (9 days 14 hours ago): Hi, I am trying to set the legend to Static, but this command seems not to work in R2022a anymore: set(gca,’LegendColorbarL isteners’,[]); Any ideas? THANKS / marcel
  • Gres (9 days 18 hours ago): In 2018b, you can get the icons by calling [hh,icons,plots,txt] = legend({‘Line 1’});
  • Yair Altman (11 days 13 hours ago): @Mitchell – in most cases the user wants a single string identifier for the computer, that uniquely identifies it with a distinct fingerprint that is different from any...
  • Mitchell (11 days 22 hours ago): Great post! I’m not very familiar with the network interfaces being referenced here, but it seems like the java-based cross-platform method concatenates all network...
  • Yair Altman (14 days 16 hours ago): Dani – You can use jViewport.setViewPosition(java .awt.Point(0,0)) as I showed in earlier comments here
  • dani (15 days 11 hours ago): hi!! how i can set the horizontal scrollbar to the leftside when appearing! now it set to right side of text
  • Yair Altman (24 days 7 hours ago): Dom – call drawnow *just before* you set hLine.MarkerHandle.FaceColorTy pe to 'truecoloralpha'. Also, you made a typo in your code: it’s truecoloralpha, not...
  • Dom (25 days 6 hours ago): Yair I have tried your code with trucoloralpha and the markers do not appear transparent in R2021b, same as for Oliver.
  • Yair Altman (28 days 13 hours ago): Ren – This is usually the expected behavior, which avoids unnecessary duplications of the Excel process in CPU/memory. If you want to kill the process you can always run...
  • Yair Altman (29 days 3 hours ago): When you use plot() without hold(‘on’), each new plot() clears the axes and draws a new line, so your second plot() of p2 caused the first plot() line (p1) to be...
  • Cesim Dumlu (35 days 11 hours ago): Hello. I am trying to do a gradient plot for multiple functions to be displayed on the same axes and each one is colorcoded by respective colordata, using the same scaling. The...
  • Yair Altman (43 days 14 hours ago): @Veronica – you are using the new version of uitree, which uses HTML-based uifigures, and my post was about the Java-based uitree which uses legacy Matlab figures. For...
  • Veronica Taurino (43 days 14 hours ago): >> [txt1,txt2] ans = ‘abrakadabra’
  • Veronica Taurino (43 days 14 hours ago): Hello, I am just trying to change the uitree node name as you suggested: txt1 = 'abra'; txt2 = 'kadabra'; node.setName([txt1,txt2]); >> "Unrecognized method, property, or...
  • Yair Altman (46 days 14 hours ago): The version of JGraph that you downloaded uses a newer version of Java (11) than the one that Matlab supports (8). You need to either (1) find an earlier version of JGraph that...
Contact us
Undocumented Matlab © 2009 - Yair Altman
This website and Octahedron Ltd. are not affiliated with The MathWorks Inc.; MATLAB® is a registered trademark of The MathWorks Inc.
Scroll to top