• 締切済み

Stringの100と100.0を同一とみなす方法

とあるフレームワークで計算するメソッドを通して計算させると、引数によって有効桁までのStringが戻り値として返されます。 そのStringの戻り値を使用して処理を分岐させたいのですが、幾分有効桁に問題があります。 (例) String p_str1 = "100" String p_str2 = "100.0" このp_str1とp_str2を等しいとみなしたいのですが、愚直に末尾から順番に文字を取り出し、最後の桁が0の場合は切り捨て(直前が.ピリオドの場合はピリオドモ含めて)てするような方法しか思いつきません。 それ以外にp_str1とp_str2を等しいとみなす方法はないでしょうか? よろしくお願いいたします。

みんなの回答

  • luckymako
  • ベストアンサー率55% (29/52)
回答No.7

No.5です。 有効桁という表現をしてしまいましたが、誤りです。 有効桁数を指定するものではなく、誤差の範囲を指定しています。 切捨ての桁数指定とでも言いますか... 頭から3桁とか指定桁しか見ないということではないということです。 つまり、 100.5 と 100 1000000000.5 と 1000000000 の両方で prec = 0 で渡せば true が prec = -1 で渡せば false が 返ってきます。 prec = -1 の場合、渡された値の差の絶対値が 約0.1 以下だったら true それ以上ならば false を返ります。 丸め誤差と書いたのは、例えば差が0.1等の場合、浮動小数点型では厳密に表すことができないために、正しく比較されないという意味です。この場合は prec の指定を大きくすることで解決することができます。 ちなみに long だと -9223372036854775808 ~ 9223372036854775807 double だと -1.7976931348623157E308 ~ 1.7976931348623157E308 この範囲から外れる大きさの入力がありますか? また有効桁数は何桁必要ですか? 値が上記範囲外で有効桁数が16~18桁以上必要であれば BigDecimal を使うのがよいと思います。 この範囲内なら先に書いた方法でも対応できるかと思います。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.6

>インプットデータの桁数変更はありえるためその場合は辛いところです。 桁数変更があり得るなら、そのようにコーディングすればよいだけですよね。 機械的には "100" と "100.0" は「異なる」ものなので、それを「等しい」とみなす方法については要件次第です。 ANo.5 の方の回答のように、有効桁数を折り込んだメソッドにすれば対応できそうに思われますが。

  • luckymako
  • ベストアンサー率55% (29/52)
回答No.5

こんなんでどうですか? public static void main(String[] args) {  String p_str1 = "100"  String p_str2 = "100.0"  System.out.println(eq(p_str1, p_str2, 0)); } public static boolean eq(String s1, String s2, int prec){  double d1 = Double.valueOf(s1);  double d2 = Double.valueOf(s2);  return Math.abs(d1 - d2) < Math.pow(10, prec); } precに有効桁を指定します。 0なら小数点以下無視 -1なら少数第一位まで -2なら少数第二位まで ただし、浮動小数点演算なので丸め誤差があります。

lahm
質問者

お礼

回答が遅れまして申し訳ございません。 100と100.0に関しては問題ないですね。 しかし、インプットデータの桁数によっては、結構桁数が大きくなってしまうことがあります。 丸め誤差に関しては、現在のところはインプットデータの桁数は問題ない桁数ですが、将来的にそのままかどうかわかりません。 Math.powメソッドは今まで使用したことがありませんでしたので、勉強になりました。 ありがとうございます。

  • neko_noko
  • ベストアンサー率45% (146/319)
回答No.4

こういうのは正規表現使うとよかとです。 //正規表現で「.00…0」を除去して同じ文字かチェック(ざっと動作チェック済み)   Pattern p =Pattern.compile("\\.0+$"); //このパターンの正規表現を使う      String p_str1 = "100"   String p_str2 = "100.000"      //「.0…0」を取り除く。念のため両方の文字を変換している   String s1 = p.matcher(p_str1).replaceAll(""); //""に置換して取り除く   String s2 = p.matcher(p_str2).replaceAll(""); //      //チェック   if (s1.equals(s2)){    System.out.println("Equal");   } else{    System.out.println("Not Equal");   } 正規表現は「\.」「0+」「$」を組み合せたものです。 「\.」はピリオド(小数点)を表し、「0+」は0の繰り返し、 「$」はそこで文字が終了、ということになります。 つまり、小数点以下0だけが最後まで続く、となり、「.00…0」と一致します。 あとは、それと一致した部分(つまり「.00…」の部分)を空文字""で置換することで 除去してるわけです。 正規表現やそれを使うクラスはあまり詳しくないので、 他にもっと良いやり方があるかもしれないのですが… まあ、何かの参考にでもなればと。

参考URL:
http://www.hellohiro.com/regex.htm
lahm
質問者

お礼

回答が遅れまして申し訳ございません。 正規表現は不得意で、あまり知らなかったのですが、 かなりシンプルかつわかりやすく実装できますね。 古いJRE上での動作は考えていないので、問題ないです。 よい勉強になりました。 ありがとうございます。

回答No.3

/** たま~にこういったのにマジレスすると、復習になっていいですね。 (Tigerにて動作確認済。) */ class AntiTacit{  static public void main(String... henkan){   String p_str1 = "100";   String p_str2 = "100.0";   System.out.println("変換前   " + p_str1 + " " + p_str2);   // 文字列から基本データ型の値を取得。   int p_str1_int = Integer.parseInt(p_str1);   double p_str2_d = Double.parseDouble(p_str2);   // 文字列からオブジェクトを生成直後にアンボクシング。   double p_str2_d_unb1 = new Double(p_str2);   double p_str2_d_unb2 = Double.valueOf(p_str2);   // 明示的にキャスト。   int p_str2_d_int = (int)p_str2_d;   int p_str2_d_unb1_int = (int)p_str2_d_unb1;   int p_str2_d_unb2_int = (int)p_str2_d_unb2;   // 数学関数を使用。   long p_str2_d_round = Math.round(p_str2_d);   // 4通りとも同じ結果となることを一気に判断。   if(p_str1_int == p_str2_d_int &&    p_str1_int == p_str2_d_unb1_int &&    p_str1_int == p_str2_d_unb2_int &&    p_str1_int == p_str2_d_round){     System.out.println("変換後その1" + p_str1_int + " " + p_str2_d_int);     System.out.println("変換後その2" + p_str1_int + " " + p_str2_d_unb1_int);     System.out.println("変換後その3" + p_str1_int + " " + p_str2_d_unb2_int);     System.out.println("変換後その4" + p_str1_int + " " + p_str2_d_round);   }else{     // もちろん、この行は実行されない。     assert false : "\n● p_str1とp_str2を等しいとみなしませんでした。●";   }  } }

lahm
質問者

お礼

回答が遅れまして申し訳ございません。 頂きましたサンプルを色々と弄り回して動きを確認させていただきました。確かにできますね。 型変換の勉強になりました。 普段サボりがちであまりやらないところなので、理解が進みよい練習になりました。 ありがとうございます。

  • Bonjin
  • ベストアンサー率43% (418/971)
回答No.2

文字列をBigDecimalに変換して比較(compareTo)するのはどうでしょう?

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.1

parseDouble(p_str1) - parseDouble(p_str2) < 0.01 なら「等しい」とするとか?

lahm
質問者

お礼

回答が遅れまして申し訳ございません。 確かにインプットデータの制度が一律であるならばこの方法でもかまわないのですが、インプットデータの桁数変更はありえるためその場合は辛いところです。 ありがとうございました。

関連するQ&A