• 締切済み

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

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

  • lahm
  • お礼率57% (4/7)
  • Java
  • 回答数7
  • ありがとう数8

みんなの回答

  • 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

  • 計算クラスのメソッドについて

    <問題> Mainクラス mainメソッド 1)実行時に引数を2つ付けて実行する。(数字) 2)計算クラスのオブジェクトを生成。 3)argsの0番目と1番目から値を取得し、int型に変換する。 4)int型に変換した値2つを引数として、計算クラスの足し算メソ   ッドを実行し、戻り値を取得して表示する。 計算クラス 足し算メソッド(引数=int,int) 1)int型の数字を引数として2つ受け取る。 2)二つの引数の値を足し算する。 3)計算した値を戻り値とする。 *********************************************************** 上記の問題についての質問です。 最初mathくらすのメソッドを使うのかと思ったのですが、 足し算を計算するようなメソッドが無かったのでネットで検索 して見つけたcalcAdd()というメソッドを使って記述してみました。 でも「シンボルを見つけられません」のエラーが出てコンパイル 出来ないし、メソッドの使い方も違うような気がするので、 分かる方正しい記述の仕方を教えてください。 package siryou; class Keisan { int cal; int cul; public int tashizan(int a, int u) { cal = a; cul = u; int kekka = (Integer)calcAdd(cal, cul, 0); return kekka; } } class TashiHikiKakeWari { public static void main(String args[]) { Keisan ki = new Keisan(); String str1 = args[0]; String str2 = args[1]; int res1 = Integer.parseInt(str1); int res2 = Integer.parseInt(str2); ki.tashizan(res1, res2); int kekka = ki.tashizan(res1, res2); System.out.println(kekka); } } ************************************************************ calcAdd()メソッドの呼び出し方も間違っている気がするのですが、 そもそもこのメソッドって呼び出せば自動的に計算されるように なっているのですか? それとも足し算を計算する記述は別にしなければならないのでしょうか?

    • ベストアンサー
    • Java
  • クラスを使用した問題

    問題 Mainクラス 1.実行時に引数を付けて実行する。 2.判定クラスのオブジェクトを生成する。 3.args(実行時の引数)から値を取得する。 4.argsから取得した値を引数として、判定クラスのnameメソッドを実行する。 5.argsから取得した値を引数として、判定クラスのageメソッドを実行する。 6.argsから取得した値を引数として、判定クラスのbirthメソッドを実行する。 判定クラス nameメソッド(引数=String) 1.String型の引数を一つ受け取る 2.受け取った引数の値が「name」だった場合、名前を表示する。 戻り値なし。 ageメソッド(引数=String) 1.String型の引数を一つ受け取る 2.受け取った引数の値が「age」だった場合、名前を表示する。 戻り値なし。 birthdayメソッド(引数=String) 1.String型の引数を一つ受け取る 2.受け取った引数の値が「birthday」だった場合、名前を表示する。 戻り値なし。 実行結果 java NameAgeBirth name 岩田 java NameAgeBirth age 27歳 java NameAgeBirth birthday 5月16日 参考例が欲しいです。良かったら参考例をください。よろしくお願いします。

  • インターフェイス実装クラスの表示について

    /* インタフェースPlanetを実装したクラスEarth、Marsがあります。  以下の実行結果になるようにクラスAggregateへshowメソッドを  追加してください。 [実行結果] 地球 太陽系にある惑星の1つで、太陽から3番目に近い。・・・ 火星 太陽系の太陽に近い方から4番目の惑星である。・・・ */ // [Planet.java] // 実装したいPlanetクラス interface Planet {   public String getName();   public String getOutline(); } // Planetを実装したEarthクラス // [Earth.java] class Earth implements Planet {   private final String name="地球";   // getNameメソッド:戻り値String、引数無し   public String getName(){    return name;   }   // getOutlineメソッド:戻り値String、引数無し    public String getOutline(){      return "太陽系にある惑星の1つで、太陽から3番目に近い。・・・";    } } // Planetを実装したMarsクラス // [Mars.java] class Mars implements Planet {   private final String name="火星";   // getNameメソッド:戻り値String、引数無し   public String getName(){     return name;   }   // getOutlineメソッド:戻り値String、引数無し   public String getOutline(){     return "太陽系の太陽に近い方から4番目の惑星である。・・・";   } } // メインクラス // [Main.java] class Main{   public static void main(String[] args){   // Earth&Marsクラスのインスタンス化    Earth earth = new Earth();     Mars mars = new Mars();   // Aggregateクラスのインスタンス化   Aggregate aggregation = new Aggregate();   // showメソッド呼び出し:戻り値無し、引数earth・mars    aggregation.show(earth);    aggregation.show(mars); } } // [Aggregate.java] class Aggregate { // ここにshowメソッドを追加   public void show(Earth planet){     System.out.println();   }   public void show(Mars planet){     System.out.println();   }  } showメソッドに引数としてEarth planet,Mars planetを渡すというところまでは理解しています。後は星の名前と概要を表示するのですが、例えば、 showメソッド内 // ここにshowメソッドを追加 public void show(Earth planet){ String str = earth.getName(); System.out.println(str); } public void show(Mars planet){ String str2 = mars.getOutline(); System.out.println(str2); } } とすると、erathとmarsの部分が「シンボルがありません」のエラーになります。自分の認識としては、EarthクラスとMarsクラスでフィールド変数を宣言しているので使えるのでは?と思っていたのですが、全然違うようです。どなたかどちらかのコード例を表記して頂けないでしょうか?よろしくお願い致します。

    • ベストアンサー
    • Java
  • ostringstreamからCの文字列を得る方法

    ostringstreamからCの文字列を得る方法について質問です。 ostringstreamのstr()メソッドを使えば、string型が得られると思うのですが、 以下の様にすると期待する様な結果が得られません。 ostringstream hoge; hoge << "HOGE" << "FUGA"; const char* p; p = hoge.str().c_str(); // NG str()メソッドで取得した結果を一旦string型に入れると期待する文字列を得る事が出来ます。 string tmp = hoge.str(); p = tmp.c_str(); // OK なぜp = hoge.str().c_str();では期待する結果("HOGEFUGA")を得る事が出来ないのでしょうか? コンパイラはVC++ 2010 Express Editionです。 よろしくお願いします。

  • Stringのフォーマットの変換方法(Java)

    Java実行時の引数として渡した14桁の数値(文字列)を、 ----- yyyy-mm-dd hh:mm:ss ----- の形式にフォーマット変換したいです。 (日時のように書いてますが、型はDateやTimestampではなくStringのままでもOK) 文字列をsubstringメソッドで区切って、 その後に「-」や「:」と+で文字列連結させる方法も考えたのですが、 そのようにせずにもう少しシンプルに変換する方法はありませんでしょうか?

    • ベストアンサー
    • Java
  • charで宣言した変数をstringへの代入で

    wchar_t cOrg[128]と宣言している変数にstringで宣言しているstrを cOrg[i] = str[i]; このように代入することはできたのですが、 char cAns[ 128 ]; このように宣言した変数の値をstrの41番目と42番目に 次のように入れようとするとエラーが出ます。 str[41]=cAns[1]; str[42]=cAns[2]; (エラー内容) \Form1.h(428): error C2664: 'System::String::String(wchar_t,int)' : 1 番目の引数を 'wchar_t [128]' から 'wchar_t' に変換できません。(新しい機能 ; ヘルプを参照) このような代入はできないのでしょうか? プログラムの詳細は下のようなものです。 wchar_t cOrg[128],*p; String^ str; String^ str2; int i; int iVal1,iVal2,iTotal = 0,iHosu; char cAns[ 128 ]; str = this->textBox1->Text; for(i=0;i<41;i++) { cOrg[i] = str[i]; } -------(中略)------------------------------------------ iHosu = ~iTotal; // 1の補数 iHosu++; // +1 iHosu = iHosu & 0x00FF; sprintf( cAns, "%s%02X%c", cOrg, iHosu, 0x22 ); str[41]=cAns[1]; str[42]=cAns[2];

  • 文字列の種類判定の方法について

    引数のStringが、「すべてアルファベット」か「日本語(ひらがな、カタカナ、漢字)を含む」かによって分岐処理をさせたいと思っています。 ネットを調べると、Character.isLetterが使えそうかと思ったのですが、これは1文字のみの判定のようですね。 Stringを一度に判定するメソッドはありませんか? なければ、Stringを1文字ずつ分けて判定していくしかないんでしょうか。 つまらない質問ですが、よろしくお願いします。

  • 有効数字について

    有効数字について例えば1.7657×3.23というような式があり、1.7657はそれまでの計算で出た、 途中計算の値だとします。また有効数字は3桁であるとします。 有効数字3桁なので1.7657は有効数字4桁の値にするのですが、この場合末尾の7を切り捨てるのですか?四捨五入するのですか? ちなみにZ会の参考書は切り捨てのほうが一般的と書いています。 大学入試では切り捨て派と四捨五入派がいることを考慮して末尾の誤差は考慮して採点してくれるのでしょうか。 また有効数字4桁とか気にせず計算し最後に四捨五入して有効数字3桁にしたほうが安全でしょうか。

  • クラスやメソッドが理解できません

    今javaを勉強中なのですが、クラスやメソッドで生きず待ってしまいました。 メソッドの定義は 戻り値の型 メソッド名(引数リスト) {  文;  ・・・ return 式;  } ですが、メソッドから返されえる値を戻り値といますよね?呼び出し元に値を返すってどういうことなのでしょうか? int getNum() { System.out.println("調べました") return num; } たとえば、上記のようなものですが。もしも、このメソッドを呼び出すと、”戻り値”が戻ってくるわけですが、これはgetNumという変数のなかに計算式が入っている?という考え方でいいのでしょうか? よろしくお願いいたします。

    • ベストアンサー
    • Java
  • 文字の表示

    オブジェクトを受け取るメソッド ↓は引数にString型のオブジェクトを指定するプログラムです public class Sample { public static void main(String args[]) { String str = "abcd"; change(str); System.out.println(str); } private static void change(String str) { str = "efgh"; } } 私の中ではefghがでると思っていたんですが・・ これを実行してみると変数strに最初に代入した文字列が表示されるんです! なぜですか? できれば理由を教えてください 回答よろしくお願いします

専門家に質問してみよう