How to fprintf of the array of floating-point numbers
167 ビュー (過去 30 日間)
古いコメントを表示
I have an array of the floating-point numbers, let say
A = [ 1 2.2 3.33; 44 55.5 6.666];
The number of row/colums as well as the number of digits before and after the decimal point are vary.
I need to find the "format" %X.Yf, to properly fprintf this array:
fprintf(%X.Yf, A).
It is alright to print the array uniformly: all data have the same number of digits after the decimal point:
A =
1.000 2.200 3.330
44.000 55.500 6.666
I can find the maximum number of digits across array's data:
tmp1 = arrayfun(@num2str,A,'UniformOutput', false);
tmp2 = cellfun((@numel),tmp1);
max_length = max(tmp2(:));
max_length defines X+Y in the "format", but I need to find the Y.
Do I over-complicate the implementation?
Any help, please?
Thank you,
Lev
0 件のコメント
採用された回答
Stephen23
2018 年 3 月 26 日
編集済み: Stephen23
2018 年 3 月 26 日
Of course there is no correct answer because these are binary floating point values, but here is one solution that gives the "least unexpected" output. It assumes double values and upto 15 significant figures.
arr = [ 1 2.2 3.33; 44 55.5 6.666];
chr = reshape(sprintf('%.14e',abs(arr)),[],numel(arr)).';
sgf = sum(cumsum('0'~=chr(:,[16:-1:3,1]),2)>0,2); % significant figures for each value
pwr = 1+sscanf(chr(:,17:end).','e%d'); % 1 + value magnitude
dgt = max(sgf-pwr); % longest decimal digits
len = max(pwr)+dgt+1; % longest string length
fmt = sprintf(' %%%d.%df',len,dgt); % core format string
fmt = [repmat(fmt,1,size(arr,2)),'\n']; % repeat format string
fprintf(fmt,arr.')
Which prints this:
1.000 2.200 3.330
44.000 55.500 6.666
3 件のコメント
Stephen23
2018 年 3 月 26 日
Well spotted. That change should make it robust against large values without decimal digits.
Image Analyst
2018 年 3 月 26 日
But I thought he didn't want that. He already had that. He started with 3 decimal places and trailing zeros, but I thought he wanted
A =
1. 2.2 3.33
44. 55.5 6.666
so that the number of decimal places on the right varied, just exactly like he had in the definition of A:
A = [ 1 2.2 3.33; 44 55.5 6.666];
which has no trailing zeros. I thought that when he said he needed Y to vary in %X.Yf that it meant that Y should be 0 for some numbers, 1 for other numbers, and 2 or 3 for other numbers depending on when the zeros started for each number.
その他の回答 (2 件)
Image Analyst
2018 年 3 月 26 日
Will this work for you?
A = [ 1 2.2 3.33; 44 55.5 6.666]
for row = 1 : size(A, 1)
fprintf('%7.3f ', A(row, :));
fprintf('\n');
end
You'll see
1.000 2.200 3.330
44.000 55.500 6.666
2 件のコメント
Image Analyst
2018 年 3 月 26 日
It doesn't vary. It always uses the full mantissa length. See Walter's example where you might think that 3.33 has only two decimal places, but it really has many more than that if you print them all out.
If you want to find where you have a certain number of zeros in a row, like 3 or something, and then chop off the number starting at the first zeros, then you'll have to convert the number to a string and look for zeros, and print the string. For example:
str = sprintf('%.999g', 3.33) % 3.3300000000000000710542735760100185871124267578125
threeZeros = strfind(str, '000');
if ~isempty(threeZeros)
str = str(1:threeZeros-1)
end
fprintf('%s\n', str);
Walter Roberson
2018 年 3 月 26 日
>> fprintf('%.999g\n', 3.33)
3.3300000000000000710542735760100185871124267578125
that is 49 digits after the decimal place.
All of the entries with value between 2 and 4 will have the same number of digits after the decimal place, except the entries that happen to involve powers of 2 denominators in the fractions, such as 3.3125 (3 + 5/16) as happens for the 44 and 55.5 entries. For entries with value between 1 and 2, add one decimal place (i.e, 50 after the decimal point); for each power of 2 above that subtract 1 decimal place. You can use log2() to calculate the grouping. Basically, floor(log2(value)) + 50 is the number of decimal places after the decimal point, except for the cases that happen to involve M/2^N for some integer M and N.
2 件のコメント
Stephen23
2018 年 3 月 26 日
編集済み: Stephen23
2018 年 3 月 26 日
@Lev Vitkin: the code you wrote is limited to 3 decimal places, so what is the point in that? Your code does not resolve your original question "I need to find the "format" %X.Yf... I need to find the Y." You just fixed Y==3, so if you are happy with that then what is the point of the question?
Your code is not very robust, and could be simplified, e.g.:
ceil(log10(max(1,abs(A)*(1+eps))))
better replaced with
1+fix(log10(max(1,abs(A))))
Note also that your code does not calculate Y (of your original question) anyway, because your concept for calculating lFrac is flawed. Try it with intermediate zeros and you will see that it will not work:
>> A = [1.001,22.002,333.003]
>> tmp = 1000*rem(A,1)2.00000 3.00000
>> tmp = ceil(log10(max(1,abs(tmp)*(1+eps))))
>> lFract = max(tmp(:))
lFract = 1
Do those numbers require one decimal digit, or three? Note that my answer correctly identifies that these require three decimal digits:
fmt = '%7.3f %7.3f %7.3f\n'
and prints this:
1.001 22.002 333.003
If you want code that actually adjusts to the precision of the numbers then see my answer.
参考
カテゴリ
Help Center および File Exchange で Characters and Strings についてさらに検索
製品
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!