LS-DYNA用の浮動小数点数をフォーマット
LS-DYNAのキーワードファイルを書きだすプログラムを書いたところ、浮動小数点数を固定文字数(10文字)にフォーマットする所でつまづいた。 具体的には
- String.formatやDecimalFormatの動作が遅い(String.formatよりはDecimalFormatのほうが速いが)
- 文字数を10文字に制限することが難しい(絶対値の大小比較を行なって桁数ごとに条件分岐をしても、四捨五入によって意図しない文字数(11文字)になる)
という問題にあたった。そこでdoubleから長さ10の文字列を力技で書きだすロジックを自作した。特徴は以下の通り。
- 正の時は先頭にスペース、負の時は先頭に"-“を入れる
- 10文字の制限の中で最も有効桁数が大きくなるようにフォーマット
- 四捨五入はしない!
- DecimalFormatの15倍高速(もう少し工夫はできるが)
private static String formatFloat10(double d){
char[] c = new char[10];
double a;
if(d == 0.0){
return " 0.0000000";
}
if(d < 0){
c[0] = '-';
a = -d;
}else{
c[0] = ' ';
a = d;
}
int m = (int)Math.floor(Math.log10(a));
if(m <= -100){
for(int i = 1; i < 1 - m; i++) a *= 10;
c[1] = (char)('0' + Math.floor(a));
a = (a - Math.floor(a)) * 10;
c[2] = '.';
for(int i = 3; i < 5; i++){
/*c[i] = (char)('0' + Math.floor(a));
a = (a - Math.floor(a)) * 10;*/
double b = Math.floor(a);
c[i] = (char)('0' + b);
a = (a - b) * 10.0;
}
c[5] = 'e';
c[6] = '-';
c[7] = (char)('0' + (-m) * 0.01);
c[8] = (char)('0' + (-m * 0.1) % 10);
c[9] = (char)('0' + (-m) % 10);
}else if(m <= -10){
for(int i = 1; i < 1 - m; i++) a *= 10;
c[1] = (char)('0' + Math.floor(a));
a = (a - Math.floor(a)) * 10;
c[2] = '.';
for(int i = 3; i < 6; i++){
double b = Math.floor(a);
c[i] = (char)('0' + b);
a = (a - b) * 10.0;
}
c[6] = 'e';
c[7] = '-';
c[8] = (char)('0' + (-m) * 0.1);
c[9] = (char)('0' + (-m) % 10);
}else if(m <= -4){
for(int i = 1; i < 1 - m; i++) a *= 10;
c[1] = (char)('0' + Math.floor(a));
a = (a - Math.floor(a)) * 10;
c[2] = '.';
for(int i = 3; i < 7; i++){
double b = Math.floor(a);
c[i] = (char)('0' + b);
a = (a - b) * 10.0;
}
c[7] = 'e';
c[8] = '-';
c[9] = (char)('0' - m);
}else if(m <= -1){
c[1] = '0';
c[2] = '.';
a *= 10;
for(int i = 3; i < 10; i++){
double b = Math.floor(a);
c[i] = (char)('0' + b);
a = (a - b) * 10.0;
}
}else if(m <= 6){
for(int i = 1; i < m + 1; i++) a *= 0.1;
for(int i = 1; i < 10; i++){
double b = Math.floor(a);
c[i] = (char)('0' + b);
a = (a - b) * 10.0;
if(i == m + 1){
c[++i] = '.';
}
}
}else if(m <= 9){
for(int i = 1; i < m + 1; i++) a *= 0.1;
c[1] = (char)('0' + Math.floor(a));
a = (a - Math.floor(a)) * 10;
c[2] = '.';
for(int i = 3; i < 8; i++){
double b = Math.floor(a);
c[i] = (char)('0' + b);
a = (a - b) * 10.0;
}
c[8] = 'e';
c[9] = (char)('0' + m);
}else if(m <= 99){
for(int i = 1; i < m + 1; i++) a *= 0.1;
c[1] = (char)('0' + Math.floor(a));
a = (a - Math.floor(a)) * 10;
c[2] = '.';
for(int i = 3; i < 7; i++){
double b = Math.floor(a);
c[i] = (char)('0' + b);
a = (a - b) * 10.0;
}
c[7] = 'e';
c[8] = (char)('0' + m * 0.1);
c[9] = (char)('0' + m % 10);
}else{
for(int i = 1; i < m + 1; i++) a *= 0.1;
c[1] = (char)('0' + Math.floor(a));
a = (a - Math.floor(a)) * 10;
c[2] = '.';
for(int i = 3; i < 6; i++){
double b = Math.floor(a);
c[i] = (char)('0' + b);
a = (a - b) * 10.0;
}
c[6] = 'e';
c[7] = (char)('0' + m * 0.01);
c[8] = (char)('0' + (m * 0.1) % 10);
c[9] = (char)('0' + m % 10);
}
return new String(c);
}