我在Matlab中为特定的CFD代码编写了一个网格平滑器。网格数据文件的要求非常严格,因此数字格式必须非常具体。一个四边形单元的定义如下(其中第二行是x坐标,第三行是y坐标)。
ELEMENT 14 [ 1Q] GROUP 0
5.000000 10.00000 10.00000 5.000000
2.000000 2.000000 4.500000 4.500000
如您所见,每个数字恰好占用8个字符。一旦整个网格通过我的平滑器,我需要将数字写回文件。我最接近这个数字格式的是以下运算符:
%#7.7克
我认为我不能使用%f,因为这指定了小数点后的位数,在我的情况下变化(我的坐标从小于1变为超过100)。这个操作员给我的唯一问题是当我的数字小于1时,它只保留7个sig figs,数字最终为9个字符;例如:
0.9313373
有没有人知道正确的运营商,或者有解决方法?非常感谢。
答案 0 :(得分:1)
这是我能想到的唯一解决方法:
A = [1.12341234 .12341234 20.12341234 5 10];
% Create a precision mask
maxwidth = 8; % Max width, characters
mask = maxwidth(ones(size(A))) - 1; % Initialize mask, account for decimal
mask(A < 1) = maxwidth - 2;
% Stack the vectors and weave them
temp = [mask(:)';A(:)'];
temp = temp(:);
test = sprintf('%#7.*g ', temp);
返回:
test =
1.123412 0.123412 20.12341 5.000000 10.00000
这是一个令人讨厌的额外步骤,但我们可以利用sprintf
的能力来获取星号,以便引用输入列表中的参数。由于我的sprintf
调用和测试用例的设置方式,我将掩码和数据编织在一起,以便sprintf
看到精度说明符和数据交替。如果您将原始temp(:)
矩阵传递给temp
,则sprintf
调用是必要的,因为它会读取数据列主要内容,因此会执行相同的操作。我添加了它,因此行为更明确。
如何为您的实际打印例程制定sprintf
调用将取决于您正在做什么,但这至少应该帮助您。
Edit1 :要展开,上述操作相当于:
a = sprintf('%#7.*g ', temp(1), temp(2));
b = sprintf('%#7.*g ', temp(3), temp(4));
c = sprintf('%#7.*g ', temp(5), temp(6));
d = sprintf('%#7.*g ', temp(7), temp(8));
e = sprintf('%#7.*g ', temp(9), temp(10));
test = [a b c d e];
Edit2 :已更新为帐户的整数值
Edit3 :请注意,目前这仅适用于正数
答案 1 :(得分:1)
如果您的8个字符中只有4位精度(.
之后的小数部分),并且网格读取程序可以处理填充0
(即它是否可以读取值)像007.2365
一样正确),那么最简单,最快捷的选择就是只使用格式说明符。
例如,让我们定义一个具有不同数量级的输入a
:
a=[ 1 234 7 ;
12 2 0.123456789 ;...
5 2.36 0.0024 ] ;
您的最高数字是234,因此小数部分留下4位数。如果您接受矩阵中所有数字的精度,那么您只需设置一个简单的指令:
fmt='%08.4f %08.4f %08.4f\n'; %// hard coded format specifier
sprintf(fmt,a.') %'// we transpose a to keep the same shape in the output since sprintf is column major.
ans =
001.0000 234.0000 007.0000
012.0000 002.0000 000.1235
005.0000 002.3600 000.0024
如果您事先不知道数据的最大数量级,您可以通过编程方式设置格式说明符:
nDigitTotal = 8 ;
nmax = ceil( log10(max(a(:))) ) ; %// max order of magnitude of numbers in "a"
f = sprintf('%%0%d.%df',nDigitTotal,nDigitTotal-nmax-1) ; %// format spec for 1 number
fmt = [f '\t' f '\t' f '\n'] ; %// format spec for a line of 3 numbers
s = sprintf(fmt,a.')
将给出与上述相同的结果。 添加一项检查以确保矩阵中没有极端值会影响您的精确度。
最后,如果该精度和/或前导零不适合您,您可以采用更精细的解决方案。我非常喜欢设置掩码的excaza的想法,以指定每个数字的精度。我将生成我自己的版本,略有不同,它可以解释任何精度的数字并允许数组输出。然而,如果你最终使用这个解决方案,那么excaza应该归功于excaza,因为他是这种演变的灵感来源:
a = a.' ; %'// transpose from beginning/ thats done
nDigitTotal = 8; %// Total number of characters
mask = nDigitTotal(ones(size(a))) ; %// Create mask
nOrder = floor( log10(a) ) ; %// find order of magnitude of each element in the matrix
mask = mask - nOrder.*(nOrder>0) -1 ; %// adjust mask according to "nOrder" (only for nOrder>0)
temp = [mask(:)';a(:)']; %// Stack the vectors and weave them
f = '%7.*f' ; %// basic format spec
fmt = [f '\t' f '\t' f '\n'] ; %// build your line
sprintf(fmt,temp) %// go for it
会给你:
ans =
1.0000000 234.00000 7.0000000
12.000000 2.0000000 0.1234568
5.0000000 2.3600000 0.0024000
注意:使用格式说明符分隔符中的正常空格('\t'
)替换制表符(' '
),具体取决于您的网格划分软件所期望的内容。