Matlab printfの書式指定と使い方


MATLAB fprintf関数の書式指定と使い方:詳細解説

はじめに

MATLABは強力な数値計算環境ですが、計算結果やプログラムの途中経過を整形して表示したり、ファイルに保存したりする際に、単に変数の中身をそのまま出力するだけでは不十分な場合があります。特に、データを特定のフォーマット(例えば、表形式、固定小数点数、指数表示など)で出力したい場合や、他のプログラムで読み込める形式でファイルに書き出したい場合には、より柔軟な出力制御が必要になります。

ここで活躍するのが、C言語のprintf関数に由来するMATLABのfprintf関数です。fprintf関数は、書式指定文字列(format specification string)と呼ばれる特殊な文字列を使って、数値、文字、文字列などをどのように整形して出力するかを細かく制御できます。この機能により、プログラマは出力形式を自由にカスタマイズし、見やすいレポートを作成したり、標準的なデータフォーマットでファイルを生成したりすることが可能になります。

本記事では、MATLABにおけるfprintf関数の基本的な使い方から、書式指定文字列の詳細な記述方法、ファイルへの出力、配列の扱い、関連関数であるsprintfとの比較、そして使用上の注意点まで、網羅的に解説します。約5000語というボリュームで、具体的な例を多数交えながら、fprintfを使いこなすための知識を提供します。

fprintf関数の基本構文

fprintf関数は、指定されたファイル(または標準出力)に、書式指定されたデータを書き出すための関数です。最も基本的な構文は以下のようになります。

matlab
fprintf(fileID, formatSpec, A1, ..., An)

各引数の意味は以下の通りです。

  • fileID: データを書き出す対象を指定する識別子です。
    • 整数値 1 を指定すると、MATLABのコマンドウィンドウ(標準出力)に出力されます。これは最も一般的に使用される形式です。
    • 整数値 2 を指定すると、標準エラー出力に出力されます。
    • fopen関数でファイルを開いたときに返されるファイル識別子を指定すると、そのファイルに出力されます。
  • formatSpec: 書式指定文字列です。出力するデータの型、表示形式、幅、精度などを指定します。後ほど詳細に解説します。
  • A1, ..., An: formatSpecで指定された書式に従って出力されるデータ(変数や値)です。これらの引数は可変個であり、formatSpec中の書式指定子の数と対応している必要があります。

fprintf関数は、書き込まれたバイト数(改行文字なども含む)を返します。書き込みに失敗した場合は負の値(-1など)を返します。この戻り値を変数で受け取ることも可能ですが、多くの場合、単に出力を行いたいだけであれば戻り値は無視されます。

例:コマンドウィンドウへの基本的な出力

matlab
name = 'Alice';
age = 30;
fprintf(1, 'Hello, %s! You are %d years old.\n', name, age);

このコードを実行すると、コマンドウィンドウに以下のように表示されます。

Hello, Alice! You are 30 years old.

ここで、1 は標準出力(コマンドウィンドウ)を、'Hello, %s! You are %d years old.\n' は書式指定文字列を、nameage は出力されるデータ(引数)を表しています。%s は文字列、%d は整数を出力するための書式指定子です。\n は改行を示すエスケープシーケンスです。

標準出力 (コマンドウィンドウ) への出力

fprintf関数を最も手軽に使う方法は、fileID1 を指定してコマンドウィンドウに出力することです。これは、プログラムのデバッグ情報を表示したり、簡単な結果を即座に確認したりする際に便利です。

“`matlab
% 数値の出力
pi_val = pi;
fprintf(1, ‘Value of pi: %f\n’, pi_val); % 浮動小数点数

% 文字列の出力
str = ‘MATLAB’;
fprintf(1, ‘Software: %s\n’, str); % 文字列

% 整数の出力
count = 100;
fprintf(1, ‘Total count: %d\n’, count); % 整数

% 複数の型を組み合わせた出力
value1 = 123.45;
value2 = 67;
fprintf(1, ‘First value: %f, Second value: %d\n’, value1, value2);
“`

これらのコードは、それぞれ指定された書式でコマンドウィンドウに出力を表示します。1 を省略して fprintf(formatSpec, A1, ...) と記述することも可能ですが、明示的に 1 を指定する方が可読性が高まります。

ファイルへの出力

計算結果や大量のデータをファイルに保存したい場合は、fprintf関数を使ってファイルに書き込みます。この場合、fileIDには fopen関数で取得したファイル識別子を指定します。ファイルへの書き込みには、以下のステップが必要です。

  1. fopen関数でファイルを開く: ファイル名と、どのような操作を行うかのモードを指定します。
  2. fprintf関数でファイルに書き込む: 開いたファイルのfileIDを指定してデータを書き込みます。
  3. fclose関数でファイルを閉じる: ファイル操作が完了したら、必ずファイルを閉じます。これにより、バッファリングされていたデータが確実にファイルに書き込まれ、ファイルが正しく閉じられます。

fopen関数の使い方

fopen関数の基本的な構文は以下の通りです。

matlab
fileID = fopen(filename, permission);

  • filename: 開くファイルの名前(パスを含む場合もある)を文字列で指定します。
  • permission: ファイルを開くモードを指定する文字列です。主なモードは以下の通りです。
    • 'r': 読み取り専用。ファイルが存在しない場合はエラー。
    • 'w': 書き込み専用。ファイルが存在する場合は内容を破棄して新しく作成。存在しない場合は新規作成。
    • 'a': 追記専用。ファイルが存在する場合は末尾に追記。存在しない場合は新規作成。
    • 'r+': 読み書き両用。ファイルが存在しない場合はエラー。
    • 'w+': 読み書き両用。ファイルが存在する場合は内容を破棄して新しく作成。存在しない場合は新規作成。
    • 'a+': 読み書き両用。ファイルが存在する場合は末尾に追記。存在しない場合は新規作成。

他にもバイナリモードを指定する 'b' (例: 'wb') や、アップデートモードを指定する 'u' などがありますが、テキストデータを書式指定して書き出す場合は 'w''a' がよく使われます。

fopen関数は、ファイルが正常に開けた場合はファイル識別子(正の整数)を返します。ファイルが開けなかった場合は -1 を返します。そのため、ファイル操作を行う前に fileID-1 でないかを確認するのが良い習慣です。

ファイルへの書き込み例

テキストファイル output.txt にデータを書き込む例です。

“`matlab
filename = ‘output.txt’;
fileID = fopen(filename, ‘w’); % 書き込みモードでファイルを開く

if fileID == -1
error(‘Could not open file “%s” for writing.’, filename);
end

% ファイルに書き込むデータ
data1 = 123;
data2 = 45.67;
data3 = ‘Sample text’;

% fprintfを使ってファイルに書き込み
fprintf(fileID, ‘Integer data: %d\n’, data1);
fprintf(fileID, ‘Floating point data: %.2f\n’, data2); % 小数点以下2桁
fprintf(fileID, ‘String data: %s\n’, data3);
fprintf(fileID, ‘Multiple data: %d and %.1f\n’, 99, 88.8);

% ファイルを閉じる
fclose(fileID);

fprintf(1, ‘Data written to “%s”\n’, filename); % コマンドウィンドウに完了メッセージ
“`

このコードを実行すると、カレントディレクトリに output.txt というファイルが作成され、以下の内容が書き込まれます。

Integer data: 123
Floating point data: 45.67
String data: Sample text
Multiple data: 99 and 88.8

ファイルを閉じる前にプログラムが異常終了した場合、データがファイルに完全に書き込まれなかったり、ファイルが破損したりする可能性があります。そのため、fclose関数を呼び出すことは非常に重要です。エラーハンドリングをより堅牢にする場合は、try-catch-finallyブロックを使って、finallyブロック内でfcloseを呼び出すようにすると良いでしょう。

“`matlab
filename = ‘output_robust.txt’;
fileID = -1; % fileIDを初期化

try
fileID = fopen(filename, ‘w’);
if fileID == -1
error(‘Could not open file “%s” for writing.’, filename);
end

fprintf(fileID, 'This is the first line.\n');
fprintf(fileID, 'This is the second line.\n');

% ここでエラーが発生する可能性のあるコード

catch ME
% エラー処理
disp(‘An error occurred during file writing.’);
disp(ME.message);

finally
% ファイルが正常に開かれていれば必ず閉じる
if fileID ~= -1
fclose(fileID);
fprintf(1, ‘File “%s” closed.\n’, filename);
else
fprintf(1, ‘File was not successfully opened.\n’, filename);
end
end
“`

書式指定文字列の詳細 (formatSpec)

fprintf関数の強力さの核心は、formatSpec引数にあります。この文字列は、リテラル文字(そのまま出力される文字)と書式指定子(format specifier)から構成されます。書式指定子は % 文字で始まり、その後にオプションのフラグ、フィールド幅、精度、サブタイプ、そして必須の型指定子(conversion specifier)が続きます。

書式指定子の一般的な構造は以下のようになります。

%[flags][width][.precision][subType]type

各要素について詳しく見ていきましょう。

1. 型指定子 (Conversion Specifiers)

これは書式指定子の中で最も重要な部分であり、出力するデータの型と、その基本的な表示形式を指定します。必ず書式指定子の最後に記述します。

型指定子 説明
d, i 符号付き整数 (decimal) %d, %i
u 符号なし整数 (unsigned decimal) %u
o 8進数 (octal) %o
x, X 16進数 (hexadecimal)。xは小文字、Xは大文字 %x, %X
f, F 固定小数点数 (floating-point) %f, %F
e, E 指数表現 (exponential)。eは小文字、Eは大文字 %e, %E
g, G fまたはe (またはFまたはE) のうち、よりコンパクトな方を選択。後続のゼロは削除される。 %g, %G
a, A 16進浮動小数点数 (hexadecimal floating-point)。aは小文字、Aは大文字。 %a, %A
c 文字 (character) %c
s 文字列 (string) %s
p ポインタ値 (pointer)。MATLABでは数値として扱われることが多い。 %p
n (非推奨/非サポート) 現在までに書き込まれた文字数を、対応する引数(ポインタで渡された整数変数)に格納。MATLABでは直接サポートされない場合が多い。 %n
%% リテラルのパーセント記号 % を出力 %%

型指定子の例:

“`matlab
integer_val = 42;
unsigned_val = uint32(1000);
hex_val = 255; % FF
float_val = 123.456789;
char_val = ‘M’;
string_val = ‘Hello’;
pointer_val = 1234567890; % MATLABでは数値をポインタ風に表示

fprintf(1, ‘Integer: %d\n’, integer_val); % 42
fprintf(1, ‘Unsigned Integer: %u\n’, unsigned_val); % 1000
fprintf(1, ‘Octal: %o\n’, integer_val); % 52
fprintf(1, ‘Hex (lower): %x\n’, hex_val); % ff
fprintf(1, ‘Hex (upper): %X\n’, hex_val); % FF
fprintf(1, ‘Float (fixed): %f\n’, float_val); % 123.456789
fprintf(1, ‘Float (exp, lower): %e\n’, float_val); % 1.234568e+02
fprintf(1, ‘Float (exp, upper): %E\n’, float_val); % 1.234568E+02
fprintf(1, ‘Float (general): %g\n’, float_val); % 123.457
fprintf(1, ‘Character: %c\n’, char_val); % M
fprintf(1, ‘String: %s\n’, string_val); % Hello
fprintf(1, ‘Pointer (example): %p\n’, pointer_val);% 0x499602d2 (システム依存)
fprintf(1, ‘Literal percent: 50%%\n’); % Literal percent: 50%
“`

2. フラグ (Flags)

型指定子の直前(ただし幅、精度、サブタイプの前)に一つ以上のフラグを記述することで、出力の追加的な制御を行うことができます。

フラグ 説明
- 出力フィールドを左詰めします。デフォルトは右詰めです。幅指定と組み合わせて使用します。
+ 符号付き数値に対して、常に符号 (+ または -) を表示します。デフォルトでは負の数のみに符号を表示します。
(スペース) 符号付き数値に対して、正の数の前にスペースを挿入します。+フラグと同時に指定された場合は+フラグが優先されます。
0 数値の出力において、フィールド幅に合わせて先行ゼロで埋めます。幅指定と組み合わせて使用します。-フラグが指定された場合は無視されます。
# 別の形式 (alternate form) を指定します。
- 8進数の場合、ゼロでない値に先行ゼロ 0 を付加します。
- 16進数の場合、ゼロでない値に接頭辞 0x または 0X を付加します。
- a, A, e, E, f, F, g, G の場合、小数点以下がゼロのみでも小数点とその後のゼロを常に表示します。
- g, G の場合、後続のゼロを削除しません。

フラグの例:

“`matlab
num = 123;
neg_num = -456;
float_num = 7.0;
hex_num = 255;

% 左詰め (-) と幅
fprintf(1, ‘Left-aligned: %-10d |\n’, num); % 123 |
fprintf(1, ‘Left-aligned: %-10s |\n’, ‘text’);% text |

% 符号表示 (+)
fprintf(1, ‘Show sign: %+d %+d\n’, num, neg_num); % +123 -456

% スペース ( )
fprintf(1, ‘Space for positive: % d % d\n’, num, neg_num); % 123 -456

% ゼロ詰め (0) と幅
fprintf(1, ‘Zero-padded: %05d\n’, num); % 00123
fprintf(1, ‘Zero-padded: %010.2f\n’, float_num); % 0000007.00 (幅と精度が両方ある場合、0は通常数値部分に適用される)

% 別の形式 (#)
fprintf(1, ‘Hex (alternate): %#x %#X\n’, hex_num, hex_num); % 0xff 0XFF
fprintf(1, ‘Float (alternate): %#g\n’, float_num); % 7.00000
fprintf(1, ‘Float (alternate): %#f\n’, float_num); % 7.000000 (%.6f と同じになる)
“`

3. 幅 (Width)

フィールド幅は、出力される値が表示される最小文字数を指定します。数値またはアスタリスク (*) で指定します。

  • 数値: 最小幅を指定します。出力が指定された幅より短い場合は、デフォルトで右側にスペース(-フラグが指定されている場合は左側にスペース)が埋められます。出力が指定された幅より長い場合は、幅は無視され、すべての文字が出力されます。
  • ***: 幅をfprintf関数の引数で指定します。この引数は整数である必要があり、対応するデータの引数の直前に配置されます。

幅の例:

“`matlab
value = 987;

% 幅指定
fprintf(1, ‘Width 5: %5d\n’, value); % 987 (右詰め、スペース埋め)
fprintf(1, ‘Width 10: %10d\n’, value); % 987
fprintf(1, ‘Width 3 (too small): %3d\n’, 12345); % 12345 (幅は無視される)

% 幅を引数で指定 ()
width_val = 7;
fprintf(1, ‘Width from argument: %
d\n’, width_val, value); % 987
fprintf(1, ‘Width and left-align from arguments: %*-10s|\n’, 15, ‘aligned text’); % aligned text |
“`

4. 精度 (Precision)

精度は、ピリオド (.) の後に数値またはアスタリスク (*) を付けて指定します。その意味は型指定子によって異なります。

  • d, i, u, o, x, X (整数): 表示される最小桁数を指定します。元の値が指定された桁数より少ない場合は、先行ゼロで埋められます。精度がゼロ (.0) で値がゼロの場合、何も出力されません。
  • f, F, e, E, g, G, a, A (浮動小数点数):
    • f, F, e, E: 小数点以下の桁数を指定します。デフォルトは6桁です。.0を指定すると小数点以下は表示されません(ただし、#フラグがある場合を除く)。
    • g, G: 有効桁数を指定します。デフォルトは6桁です。
  • s (文字列): 出力される最大文字数を指定します。文字列が指定された文字数より長い場合、切り詰められます。
  • *: 精度をfprintf関数の引数で指定します。この引数は整数である必要があり、対応するデータの引数の直前に配置されます。

精度の例:

“`matlab
int_val = 42;
float_val = 1.23456789;
string_val = ‘abcdefghijk’;

% 整数に対する精度 (最小桁数/ゼロ詰め)
fprintf(1, ‘Int precision 5: %.5d\n’, int_val); % 00042
fprintf(1, ‘Int precision 0: %.0d\n’, 0); % (何も出力されない)

% 浮動小数点数に対する精度 (小数点以下の桁数)
fprintf(1, ‘Float precision 2: %.2f\n’, float_val); % 1.23
fprintf(1, ‘Float precision 4: %.4f\n’, float_val); % 1.2346 (四捨五入される)
fprintf(1, ‘Float precision 0: %.0f\n’, float_val); % 1

% 指数表現に対する精度 (小数点以下の桁数)
fprintf(1, ‘Exp precision 2: %.2e\n’, float_val); % 1.23e+00

% 一般形式に対する精度 (有効桁数)
fprintf(1, ‘General precision 3: %.3g\n’, float_val); % 1.23
fprintf(1, ‘General precision 5: %.5g\n’, 123.456789);% 123.46

% 文字列に対する精度 (最大文字数)
fprintf(1, ‘String precision 5: %.5s\n’, string_val); % abcde

% 精度を引数で指定 ()
precision_val = 3;
fprintf(1, ‘Float precision from argument: %.
f\n’, precision_val, float_val); % 1.235
“`

5. サブタイプ (Subtypes)

サブタイプは、数値のサイズを指定するために使用される修飾子です。C/C++のprintfと互換性のために提供されていますが、MATLABの数値型システムとは必ずしも1対1で対応しません。MATLABでは、数値は通常double型として扱われ、整数型も指定しなければdoubleになります。これらの修飾子は、MATLABが内部で型を変換する際にヒントとして機能します。

サブタイプ 説明
h C/C++の short int または unsigned short int に対応。
l C/C++の long int または unsigned long int、あるいは double に対応。MATLABでは double に対してよく使用されます。
ll C/C++の long long int または unsigned long long int に対応。
L C/C++の long double に対応。
j C/C++の intmax_t または uintmax_t に対応。
z C/C++の size_t に対応。
t C/C++の ptrdiff_t に対応。

MATLABでこれらのサブタイプを使う機会は少ないですが、例えば%ldのように使用できます。MATLABは内部的に適切な変換を行います。

サブタイプの例:

matlab
long_int_val = 1234567890; % MATLABではdouble
fprintf(1, 'Long integer (l): %ld\n', long_int_val); % 1234567890

6. エスケープシーケンス (Escape Sequences)

書式指定文字列内に特殊な文字(改行、タブなど)を記述するために使用します。バックスラッシュ (\) で始まります。

シーケンス 説明
\n 改行 (newline)
\t 水平タブ (tab)
\\ バックスラッシュ
\% パーセント記号
\' シングルクォート
\" ダブルクォート
\a アラート (ベル)
\b バックスペース
\f フォームフィード
\v 垂直タブ

これらのエスケープシーケンスは、リテラル文字として書式指定文字列内に直接記述できます。

エスケープシーケンスの例:

matlab
fprintf(1, 'Line 1\nLine 2 with a \t tab\n');
fprintf(1, 'A backslash: \\, A percent: %%\n');
fprintf(1, 'Quoted string: \'Hello\'\n');

出力:

Line 1
Line 2 with a tab
A backslash: \, A percent: %
Quoted string: 'Hello'

配列の出力

MATLABは配列計算に特化した言語であるため、fprintf関数も配列の扱いに特徴があります。fprintfは、入力された配列の要素を、書式指定文字列を繰り返し適用しながら、列優先(column-major order)で処理します。

スカラー、ベクトル、行列の出力

  • スカラー: 書式指定子に対応する引数がスカラーの場合、単純にその値が出力されます。
  • ベクトル: 書式指定子に対応する引数がベクトルの場合、fprintfはベクトルの各要素に対して書式指定子を順番に適用します。
  • 行列: 書式指定子に対応する引数が行列の場合、fprintfは行列の要素を列方向に順番に(1列目の要素を上から下へ、次に2列目の要素を上から下へ、…)取り出し、書式指定子を適用します。

配列出力の例:

“`matlab
vec = [10, 20, 30];
mat = [1, 2, 3; 4, 5, 6]; % 2×3行列

% ベクトルを%dで出力 (各要素に%dが適用される)
fprintf(1, ‘Vector: %d %d %d\n’, vec); % Vector: 10 20 30

% ベクトルを異なる書式で出力 (書式指定子も繰り返される)
% fprintfはvecの要素を順番に取り出し、書式指定子’%d\t%f\n’を繰り返し適用しようとする
% しかし、vecは3要素なので、最初の要素(10)に%d、2番目の要素(20)に%fが適用された後、引数が足りなくなる
% MATLABは書式文字列を繰り返す前に引数が尽きると、それまでの出力で終了する
fprintf(1, ‘Vector elements with mixed format:\n%d\t%f\n’, vec);
% 出力:
% Vector elements with mixed format:
% 10 20.000000
% 30
% この例では、vecの最初の2要素に対して’%d\t%f\n’が適用され、3番目の要素(30)に対しては’%d’が適用される

% 行列を%dで出力 (列優先で要素を取り出し、%dを繰り返し適用)
fprintf(1, ‘Matrix (column-major):\n%d %d %d %d %d %d\n’, mat);
% 行列 mat = [1 2 3; 4 5 6] の要素は列優先で 1, 4, 2, 5, 3, 6 の順に取り出される
% 出力:
% Matrix (column-major):
% 1 4 2 5 3 6

% 行列を整形してテーブル形式で出力
% 各行を新しい行に出力したい場合、書式指定文字列と引数の数を調整する必要がある
% 例: 2×3行列を2行3列で出力
mat = [10.1, 10.2, 10.3; 20.1, 20.2, 20.3];
fprintf(1, ‘Table output:\n’);
% 各行に対してfprintfを呼び出すか、書式指定文字列を工夫する
% 各列の要素をまとめて渡す方法 (列優先)
% 1列目: 10.1, 20.1
% 2列目: 10.2, 20.2
% 3列目: 10.3, 20.3
% 書式: %.1f (1列目1行目) %.1f (2列目1行目) %.1f (3列目1行目) \n
% %.1f (1列目2行目) %.1f (2列目2行目) %.1f (3列目2行目) \n
% Argument: mat(:)’ (行列要素を1行ベクトルに変換) -> [10.1 20.1 10.2 20.2 10.3 20.3]
% この順序では意図したテーブルにならない

% 意図したテーブル形式にするためには、通常、行ごとにデータを取得し、その行の要素を引数として渡す
for i = 1:size(mat, 1) % 行数だけ繰り返す
fprintf(1, ‘%.1f\t%.1f\t%.1f\n’, mat(i, :)); % i行目の全要素を引数として渡す
end
% 出力:
% Table output:
% 10.1 10.2 10.3
% 20.1 20.2 20.3
“`

配列を扱う場合、fprintfが列優先で要素を処理すること、そして書式指定文字列が引数の要素が尽きるまで、あるいは書式指定文字列が最後まで処理されるまで繰り返される(先に尽きた方で終了する)という挙動を理解することが重要です。特に複雑な形式で配列を出力したい場合は、ループを使って行ごとや要素ごとにfprintfを呼び出すのが最も柔軟で理解しやすい方法です。

複数書式指定子と配列引数

書式指定文字列に複数の書式指定子が含まれており、引数が配列である場合、fprintfは以下のように動作します。

  1. 書式指定文字列を先頭から順に解析し、書式指定子を見つけます。
  2. 見つかった書式指定子に対応する引数として、配列から次の要素を取り出します(列優先)。
  3. このプロセスを、書式指定文字列の最後まで、または引数の配列の要素がすべて消費されるまで繰り返します。
  4. もし書式指定文字列の途中で引数が尽きた場合、処理はそこで終了します。
  5. もし書式指定文字列の最後まで処理が完了したが、まだ引数の配列に要素が残っている場合、fprintf書式指定文字列全体を最初から繰り返し、残りの引数要素を処理しようとします。

この繰り返し処理は、特に固定長のレコードやテーブル形式のデータをファイルに書き出す際に便利です。

書式文字列の繰り返し例:

“`matlab
data = [10, 1.1, 20, 2.2, 30, 3.3]; % 6要素のベクトル
% 書式: %d (整数) \t (タブ) %f (浮動小数点) \n (改行)
% この書式は2つのデータ引数を消費するごとに1行出力する

fprintf(1, ‘Data pairs:\n’);
fprintf(1, ‘%d\t%.1f\n’, data);
% dataの要素は [10, 1.1, 20, 2.2, 30, 3.3]
% 1回目の書式適用: %d に 10, %.1f に 1.1 -> “10 1.1\n”
% dataの要素は [20, 2.2, 30, 3.3] が残っている
% 書式文字列の最後まで到達したので、書式文字列全体 (%d\t%.1f\n) を繰り返す
% 2回目の書式適用: %d に 20, %.1f に 2.2 -> “20 2.2\n”
% dataの要素は [30, 3.3] が残っている
% 書式文字列を繰り返す
% 3回目の書式適用: %d に 30, %.1f に 3.3 -> “30 3.3\n”
% dataの要素はすべて消費されたので終了

% 出力:
% Data pairs:
% 10 1.1
% 20 2.2
% 30 3.3

% 行列と書式文字列の繰り返し
mat = [101, 102; 201, 202; 301, 302]; % 3×2行列
% 書式: %d (1列目) \t (タブ) %d (2列目) \n (改行)
% この書式は2つのデータ引数を消費するごとに1行出力する
% 行列の要素は列優先で [101, 201, 301, 102, 202, 302] の順に取り出される

fprintf(1, ‘Matrix output (repeating format):\n’);
fprintf(1, ‘%d\t%d\n’, mat);
% 1回目の書式適用: %d に 101, %d に 201 -> “101 201\n”
% 残りの要素: [301, 102, 202, 302]
% 書式文字列を繰り返す
% 2回目の書式適用: %d に 301, %d に 102 -> “301 102\n”
% 残りの要素: [202, 302]
% 書式文字列を繰り返す
% 3回目の書式適用: %d に 202, %d に 302 -> “202 302\n”
% 残りの要素なし、終了

% 出力:
% Matrix output (repeating format):
% 101 201
% 301 102
% 202 302
“`

このように、配列引数と複数の書式指定子を組み合わせる際には、fprintfが列優先で要素を取り出し、書式指定文字列を繰り返す挙動を正しく理解していないと、意図しない出力になってしまう可能性があります。特にテーブル形式で出力したい場合は、前述のようにループを使って行ごとに処理するのが、多くの場合最も直感的な方法です。

sprintf関数との比較

MATLABにはfprintfと非常によく似た関数としてsprintf関数があります。この2つの関数の主な違いは出力先です。

  • fprintf: 指定されたファイル(または標準出力)に書き出します。戻り値は書き込まれたバイト数です。
  • sprintf: 書式指定されたデータを文字列として生成し、その文字列を返します。ファイルへの書き出しは行いません。

sprintf関数の構文は以下の通りです。

matlab
str = sprintf(formatSpec, A1, ..., An);

引数はfprintfformatSpecと可変個引数と同じですが、fileID引数はなく、戻り値は生成された文字列 (str) です。

sprintfは、ファイルに書き出すのではなく、書式付き文字列を生成して変数に格納したい場合に非常に便利です。例えば、グラフのタイトル、軸ラベル、 Legend の文字列を作成したり、エラーメッセージやログメッセージを整形したり、データベースクエリの一部を動的に構築したりする場合などに使用されます。

sprintfの例:

“`matlab
x = 10;
y = 20.5;

% sprintfを使って文字列を生成
formatted_string = sprintf(‘Coordinates: (x=%.1f, y=%.1f)’, x, y);
disp(formatted_string); % 生成された文字列を表示
% 出力: Coordinates: (x=10.0, y=20.5)

% ファイル名やパスを動的に生成
data_id = 123;
filename = sprintf(‘data_result_%03d.txt’, data_id);
disp(filename);
% 出力: data_result_123.txt

% 配列を sprintf で文字列化 (fprintfと同様に列優先、書式繰り返し)
values = [1, 2, 3, 4];
value_string = sprintf(‘%d ‘, values);
disp(value_string); % 注意: 最後に余分なスペースが付く
% 出力: 1 2 3 4

% sprintfでテーブルのような文字列を生成 (通常はfprintfの方がファイル出力に向く)
mat = [1 2; 3 4];
table_string = sprintf(‘%d\t%d\n’, mat’); % 行列を転置して行優先にするテクニック
disp(table_string);
% 出力:
% 1 2
% 3 4
% (注意: mat’によって要素の取り出し順が [1, 2, 3, 4] となり、’%d\t%d\n’が繰り返されて正しい行/列になる)
“`

配列をsprintfで文字列化する際、fprintfと同様の列優先と書式繰り返しのルールが適用されます。もし行優先で要素を取り出して文字列化したい場合は、例のように行列を転置する (mat') というテクニックが有効です。

fprintfsprintfは、書式指定文字列の記述方法や引数の処理方法が共通しているため、一方の使い方をマスターすればもう一方も容易に理解できます。出力先がファイルか文字列かの違いだけです。

関連関数

fprintfsprintfに関連する、MATLABの他の便利な関数をいくつか紹介します。

  • fscanf: fprintfの逆の操作を行う関数です。ファイルや文字列から、書式指定に従ってデータを読み込みます。ファイルから特定のフォーマットで記述されたデータをインポートする際に非常に役立ちます。
    matlab
    % 例: ファイルから読み込み
    fileID = fopen('output.txt', 'r');
    if fileID ~= -1
    % ファイルの内容: Integer data: 123\nFloating point data: 45.67\n...
    % fscanfは指定された書式にマッチするデータを読み込む
    fmt = 'Integer data: %d\nFloating point data: %f\n';
    C = textscan(fileID, fmt); % textscanの方が柔軟だが、fscanfの例として
    % fscanfのより低レベルな使い方
    frewind(fileID); % ファイルポインタを先頭に戻す
    int_val = fscanf(fileID, 'Integer data: %d\n', 1); % 書式と読み込む要素数
    float_val = fscanf(fileID, 'Floating point data: %f\n', 1);
    fclose(fileID);
    % disp(int_val); disp(float_val);
    end
  • disp: 最も基本的な出力関数です。変数の内容を整形せずそのままコマンドウィンドウに表示します。シンプルで手軽ですが、書式制御はできません。
    matlab
    A = [1 2; 3 4];
    disp(A);
    % 出力:
    % 1 2
    % 3 4
    disp('Hello World'); % 文字列も表示
  • num2str: 数値を文字列に変換します。書式制御は限定的ですが、シンプルに数値を文字列化したい場合に便利です。精度などを指定できます。
    matlab
    num = 123.456;
    str1 = num2str(num); % '123.456' (デフォルト精度)
    str2 = num2str(num, 2); % '1.2e+02' (有効桁数2桁)
    str3 = num2str(num, '%.2f'); % '123.46' (書式指定文字列も使える)
  • mat2str: 行列をMATLAB構文の文字列に変換します。コードとして評価可能な形式で文字列を生成するのに役立ちます。
    matlab
    mat = [1 2; 3 4];
    str = mat2str(mat); % '[1 2;3 4]'

    fprintfは、これらの関数の中で最も柔軟かつ低レベルな出力制御を提供します。特定のフォーマットでの出力が求められる場合には、fprintfが主要な選択肢となります。

注意点とヒント

fprintf関数を使用する際に知っておくと良い注意点やヒントをいくつか紹介します。

  1. 書式指定子と引数の型の不一致: formatSpecで指定した書式指定子と、対応する引数のデータ型が一致しない場合、MATLABは可能な限り型変換を試みますが、意図しない結果になったり、警告が表示されたりする可能性があります。例えば、整数を指定すべきところに文字列を渡したりするとエラーになります。書式指定子と引数の型は正確に対応させるようにしましょう。
  2. 引数の数: formatSpec中の書式指定子(%で始まるもの。%%を除く)の数と、fprintfに渡す引数の数(fileID, formatSpecに続くもの)は一致させる必要があります。数が合わない場合、MATLABは警告を表示してエラーになることがあります。
  3. ファイルパスの指定: fopenでファイルを開く際、ファイル名を指定しますが、カレントディレクトリ以外の場所にファイルを作成したい場合は、絶対パスまたは相対パスを指定する必要があります。OSによってパスの区切り文字(\または/)が異なりますが、MATLABではどちらを使っても(多くの場合)正しく解釈されます。可搬性を高めるためには、fullfile関数を使ってパスを構築するのが推奨されます。
    matlab
    folder = 'results';
    filename = 'output.txt';
    full_path = fullfile(folder, filename); % OSに応じたパス区切り文字で結合
    fileID = fopen(full_path, 'w');
  4. エンコーディング: ファイルへの書き込みを行う際、テキストエンコーディング(文字コード)を意識する必要があります。fopen関数の3番目の引数でエンコーディングを指定できます(例: fopen(filename, 'w', 'n', 'UTF-8'))。特に日本語のようなマルチバイト文字を含むデータを扱う場合や、異なるOS間でファイルを共有する場合は、適切なエンコーディングを指定することが重要です。デフォルトのエンコーディングはシステムのロケールに依存します。
  5. 大きなデータやファイル: 大量のデータをファイルに書き込む場合、fprintfは逐次的な書き込みには適していますが、非常に巨大な配列全体を効率的に書き出すには、fwrite関数などの低レベルなバイナリ書き込み関数や、特定のファイル形式(例: HDF5, NetCDF, MATファイル)に特化した関数 (hdf5write, netcdf.putVar, save) を検討する方が効率的な場合があります。fprintfはテキスト形式での出力に最適です。
  6. 出力バッファ: ファイルへの書き込みは、通常、効率化のために内部バッファリングされます。fcloseを呼び出すことで、バッファ内のデータがファイルに書き込まれます。リアルタイム性を重視する場合や、プログラムがクラッシュした場合にデータの損失を最小限に抑えたい場合は、fflush(fileID)関数を使って明示的にバッファをフラッシュ(強制的にファイルに書き出し)することができます。
  7. クロスプラットフォーム互換性: 改行コードはOSによって異なります(WindowsはCRLF \r\n、Unix/Linux/macOSはLF \n)。fprintf\n を使用した場合、fopenで指定したモード(特にテキストモード 't' が暗黙的に指定されている場合)によって、MATLABがOSに応じた改行コードに自動変換してくれることがあります。しかし、バイナリモード ('b') を使用した場合や、特定のファイル形式で厳密な改行コードが必要な場合は注意が必要です。

まとめ

MATLABのfprintf関数は、計算結果やデータを見やすく整形してコマンドウィンドウに表示したり、特定のフォーマットでファイルに保存したりするための非常に強力で柔軟なツールです。書式指定文字列を使いこなすことで、数値の桁数、小数点以下の精度、フィールド幅、文字揃え、符号表示などを自由に制御できます。

本記事では、fprintfの基本的な構文から始め、標準出力とファイル出力の方法、そして書式指定文字列を構成する各要素(型指定子、フラグ、幅、精度、サブタイプ、エスケープシーケンス)について詳細に解説し、多数の具体例を示しました。また、MATLABの配列がfprintfによって列優先で処理されること、書式指定文字列が繰り返し適用される仕組み、そして似た機能を持つsprintf関数との違いについても触れました。

fprintfはC言語のprintfにルーツを持つため、C言語の書式指定に慣れているユーザーには親しみやすいでしょう。その一方で、MATLABの配列処理の特性が加わるため、特に配列を整形して出力する際には独特の注意が必要です。

この記事が、MATLABにおけるfprintf関数の使い方と書式指定の奥深さを理解し、あなたのデータ出力やファイル操作の効率と表現力を向上させる一助となれば幸いです。複雑な出力フォーマットの要求に応えるために、ぜひfprintfを積極的に活用してください。


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール