Javaで12500を1.2500にフォーマットする

Javaで12500って整数を1.2500って文字列にフォーマットする必要があったんだけど、そのために浮動小数点の除算+Formatterとかバカっぽいなー、とか思っていくつか試してみた。

  1. String.format(“%.4f”, float)
    float除算→Formatter
  2. String.format”%d.%d”, int, int)
    整数部と剰余に分割→Formatter
  3. DecimalFormat.format(“#.0000”, float)
    float除算→DecimalFormat
  4. String.replaceFirst(“(\\d{4,4})$”, “.$1”)
    String.valueOf(int)→正規表現で後ろ4文字の前にピリオド追加
  5. 4.のプリコンパイル版(Pattern.compile…)

正確に言うと値としても1.2500とか1.5000とかを扱うのだけど、浮動小数点の値を扱っているわけではないので本来使うべきはBigDecimal。しかしながら、演算子オーバーロードがないJavaでnon-primitiveな数値クラスとか使いたくないから、内部の処理は12500とか15000とか整数値でもっておいて、表示だけ小数点付きにすることにした。

いくらでもやり方ありそうだし、きっともっとかっこよくて速い書き方があるだろうけど、別にものすごい速度を求めているわけではないから5.のRegexpでいこうかと。

import java.text.*;
import java.util.regex.*;

public class Hoge {
 
  private static Pattern p = Pattern.compile("(\\d{4,4})$");
  private static int loops = 0xFFFFF;

  public static void main(String... args) throws Exception {
    long start = System.currentTimeMillis();
    System.out.printf("StringFormat Float : %s %d%n", formatter1(), System.currentTimeMillis() - start);

    start = System.currentTimeMillis();
    System.out.printf("StringFormat Integer : %s %d%n", formatter2(), System.currentTimeMillis() - start);

    start = System.currentTimeMillis();
    System.out.printf("DecimalFormat : %s %d%n", decimalformat1(), System.currentTimeMillis() - start);

    start = System.currentTimeMillis();
    System.out.printf("Regexp : %s %d%n", regexp1(), System.currentTimeMillis() - start);

    start = System.currentTimeMillis();
    System.out.printf("Precompiled Regexp : %s %d%n", regexp2(), System.currentTimeMillis() - start);
  }

  private static String formatter1() {
    String x = null;
    for (int i = 0; i < loops ; ++i) {
      x = String.format("%.4f", 12500f / 10000f);
    }
    return x;
  }

  private static String formatter2() {
    String x = null;
    for (int i = 0; i < loops ; ++i) {
      x = String.format("%d.%d", 12500 / 10000, 12500 % 10000);
    }
    return x;
  }

  private static String decimalformat1() {
    String x = null;
    DecimalFormat f = new DecimalFormat("#.0000");
    for (int i = 0; i < loops ; ++i) {
      x = f.format(12500f/10000f);
    }
    return x;
  }

  private static String regexp1() {
    String x = null;
    for (int i = 0; i < loops ; ++i) {
      x = String.valueOf(12500).replaceFirst("(\\d{4,4})$", ".$1");
    }
    return x;
  }

  private static String regexp2() {
    String x = null;
    for (int i = 0; i < loops ; ++i) {
      x = p.matcher(String.valueOf(12500)).replaceFirst(".$1");
    }
    return x;
  }
}

おおざっぱに傾向がつかめればいいかなーくらいの感じで書いているのでプログラムはかなり適当。正規表現のプリコンパイル部分なんかは測定対象から落ちちゃってるし。

[~] java -classpath . Hoge
StringFormat Float   : 1.2500 1617
StringFormat Integer : 1.2500 1155
DecimalFormat        : 1.2500 591
Regexp               : 1.2500 651
Precompiled Regexp   : 1.2500 306

にしても、String.formatは相変わらずヒドい。