6

I'm writing data to an output text file using the fprintf command in Matlab. How to write a number to the output file, for instance, 1.12345678e-001, with three digits in the exponent?

formatSpec = '%1.8e\n';

gives 1.12345678e-01, not the desired result!

There's a similar question here https://se.mathworks.com/matlabcentral/answers/100772-how-do-i-use-fprintf-to-write-numbers-in-exponential-notation-of-variable-exponent-digits-on-a-windo

But following the instructions given there didn't solve the problem!

Community
  • 1
  • 1
Emma
  • 149
  • 10

3 Answers3

7

You can use this non-regex method:

num = 0.112345678
pow = floor(log10(abs(num)));
sprintf('%.8fe%+.3d', num/10^pow, pow)

ans =
1.12345678e-001

For multiple inputs use this:

num= [.123 .456 .789];
pow = floor(log10(abs(num)));
sprintf('%.8fe%+.3d ', [num./10.^pow; pow])
rahnema1
  • 15,264
  • 3
  • 15
  • 27
  • 1
    Nice. I like this solution better than mine. – Aero Engy Jan 23 '18 at 13:23
  • @rahnema1 may be little silly question, if `num= [.123; .456; .789];` how can I format the output data in rows instead of columns? I have multiple one column arrays of double data type e.g. `x = [-0.00912036467;-0.00838289689;-0.0106730480;-0.0115961293;-0.00669082161;...]` that need to be changed to the format `x = [-9.12036467e-003; -8.38289689e-003; -1.06730480e-002; -1.15961293e-002; -6.69082161e-003;...]` – Emma Jan 23 '18 at 17:08
  • 1
    @Emma You could just modify the last line to add new line instead of a space `sprintf('%.8fe%+.3d\n', [num./10.^pow; pow])` – Aero Engy Jan 23 '18 at 18:07
  • @Emma Sorry for late reply. Sice the array is a column vector you should first transpose it. As AeroEngy pointed out you can use `\n` instead of space. `x = x.';pow = floor(log10(abs(x)));sprintf('%.8fe%+.3d\n', [x ./ 10 .^pow; pow]);` – rahnema1 Jan 23 '18 at 21:00
  • @Aero Engy that does not really give correct values, you can try it! I have solved the issue by employing for-loop and empty cell array, and wrote the result to the output file line by line : `num = [.123; .456; .789] j = cell(size(num)) pow = floor(log10(abs(num))), n = num./10.^pow, for i=1:length(n) j{i,:} =sprintf('%.8fe%+.3d', n(i,:),pow(i,:)) end j = '1.23000000e-001' '4.56000000e-001' '7.89000000e-001' ` For output: `formatSpec = '%s'; for i=1:length(num) fprintf(fileIDout,formatSpec,j{i,:}); end` – Emma Jan 23 '18 at 21:31
  • 1
    No need to loop. This should work: `num= [.123; .456; .789];num = num.';pow = floor(log10(abs(num)));fprintf(fileIDout,'%.8fe%+.3d\n', [num./10 .^pow; pow])` – rahnema1 Jan 23 '18 at 21:53
6

Not sure if this falls under the category of solution or work-around, but here it goes:

x = .123e25; % example number
formatSpec = '%1.8e\n'; % format specification
s = sprintf(formatSpec, x); % "normal" sprintf
pat = '(?<=e)[+-]\d+'; % regex pattern to detect exponent
s = regexprep(s, pat, sprintf('%+04i', str2double(regexp(s, pat ,'match')))); % zero-pad

It uses regular expressions to identify the exponent substring and replace it with the exponent zero-padded to three digits. Positive exponents include a plus sign, as with fprintf.

Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
5

This isn't the cleanest answer but you could do something like this. Basic steps are write as is, get the exponent with a regexp, re-write that portion, and replace.

formatSpec = '%1.8e'

tempStr = sprintf(formatSpec,1.12345678e-1);
oldExp  = regexp(tempStr,'e[+-]([0-9]+)$','tokens');
newExp  = num2str(str2double(oldExp{1}{1}),'%03d');
fixedStr = regexprep(tempStr,[oldExp{1}{1} '$'],newExp)

This outputs:

fixedStr =    
1.12345678e-001
Aero Engy
  • 3,588
  • 1
  • 16
  • 27
  • Well, it's probably cleaner than mine :-P – Luis Mendo Jan 23 '18 at 12:47
  • @LuisMendo I started to do something like yours but the nested regexp inside of the regexprep where killing me. I did like your use of 'match' with the `(?<=e) look behind operator – Aero Engy Jan 23 '18 at 12:52