Javaで電卓を作成する際の平方根の求め方

このQ&Aのポイント
  • Javaで電卓を作成する際、平方根を求める方法について質問があります。BigDecimal型の平方根を求めて、その結果の文字列から末尾の0を取り除く方法について教えてください。
  • また、平方根を求めるメソッド内で二分法の処理が行われていますが、除算のスケールを64に指定している理由や文字列の長さの違いについても教えてください。
  • 以上が質問の内容です。お知恵をお貸しください。
回答を見る
  • ベストアンサー

Java 電卓を作っているのですが・・・

こんにちは。 趣味でプログラミングをしているものです。 Java で電卓を再現しようとしていて、 コーディングが終わり動作を確認しているのですが、 わからないところがあるので質問させていただきました。 よろしくおねがいします。 平方根を求めるときなのですが、3や5などはある程度正確に求められている と思うのですが、 平方根を求めたとき整数になるもの 例えば9などは小数のまま表示されてしまいます。 電卓で表示され得るすべての実数について平方根を求めるには ニュートン法がよいと思うのですが・・・ 二点ほど質問させていただきます。 ------------------------------------ 質問A まず、BigDecimal型の平方根を求めて、 その toString() から得られた文字列を メソッドvalidControl( String value ) に渡すのですが その冒頭で末尾から先頭方向に続く'0' の列を取り除きたいのですが そのために、変数の中身をみてみたのがこの質問の下部のほうにある (ア) (イ) です。 sqrt(() などの演算結果でえられた文字列のうち 信頼できる範囲以下の文字列を validControl で切り取りたいのですが プロが実際に電卓を作るとしたら、 どのような処理になるのでしょうか? ------------------------------------ 質問B 平方根を求めるメソッドsqrt 内で二分法の処理では 除算のスケールを 64 に指定していますが、 実行結果(ア)(イ)の文字列の長さが異なるのは なぜでしょうか? ------------------------------------ private BigDecimal sqrt( BigDecimal value ) { BigDecimal two = new BigDecimal( "2" ); BigDecimal x = value.divide( two ); BigDecimal last_x = BigDecimal.ZERO; BigDecimal gap = x.subtract( last_x ); BigDecimal range = BigDecimal.ONE.movePointLeft( 64 ); BigDecimal t; while( gap.compareTo(range) > 0 ) { last_x = new BigDecimal( x.toString() ); //t = value.divide( x, 64, BigDecimal.ROUND_DOWN ); //(イ) //test statement t = value.divide( x, 64, RoundingMode.UP ); // (ア) // x = x.add( t ).divide( two ); gap = x.subtract( last_x ).abs(); } return x; } -------------------------------------- private String validControl( String value ) throws KETAException { String retstring = ""; boolean overflag = false; int idx1 = value.indexOf( '.' ); int gap = 0; int seisu_length = 0; // 整数部分の文字列の長さ int len = value.length(); int start = len-1; int idx2 = start; System.out.println( "(0)" + value ); System.out.println( "(1)" + String.valueOf( start ) ); while( value.charAt( idx2 ) == '0' ) { idx2 --; } if( idx2 != start ) { value = value.substring( 0, idx2 + 1 ); len = value.length(); } System.out.println( "(2)" +String.valueOf( idx2 ) ); // 以下省略 -------------------------------------- (ア) を実行したときの結果 (0) 3.000000000000000000000000000000000000 00000000000000000000000000000546875 (1)72 (2)72 --------------------------------------- (イ) を実行したときの結果 (0) 2.999999999999999999999999999999999999 999999999999999999999999999996875 (1)70 (2)70 -------------------------------------- 長文になり申しわけありませんが ご存知のかた教えていただけないでしょうか? よろしくお願いします。

noname#173931
noname#173931
  • Java
  • 回答数1
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

そのコードだとちょっと複雑かもしれませんのでこちらを参考にしてください package dentaku; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class DentakuFrame extends JFrame { private static final long serialVersionUID = 1L; JPanel contentPane = new JPanel(); BorderLayout borderLayout1 = new BorderLayout(); JTextField result = new JTextField(""); //計算結果を表示するテキストフィールド double stackedValue = 0.0; //演算子ボタンを押す前にテキストフィールドにあった値 boolean isStacked = false; //stackedValueに数値を入力したかどうか boolean afterCalc = false; //演算子ボタンを押した後かどうか String currentOp = ""; //押された演算子ボタンの名前 //フレームのビルド public DentakuFrame() { contentPane.setLayout(borderLayout1); this.setSize(new Dimension(250, 300)); this.setTitle("電子式卓上計算機"); this.setContentPane(contentPane); contentPane.add(result, BorderLayout.NORTH); //テキストフィールドを配置 JPanel keyPanel = new JPanel(); //ボタンを配置するパネルを用意 keyPanel.setLayout(new GridLayout(4, 4)); //4行4列のGridLayoutにする contentPane.add(keyPanel, BorderLayout.CENTER); keyPanel.add(new NumberButton("7"), 0); //ボタンをレイアウトにはめこんでいく keyPanel.add(new NumberButton("8"), 1); keyPanel.add(new NumberButton("9"), 2); keyPanel.add(new CalcButton("÷"), 3); keyPanel.add(new NumberButton("4"), 4); keyPanel.add(new NumberButton("5"), 5); keyPanel.add(new NumberButton("6"), 6); keyPanel.add(new CalcButton("×"), 7); keyPanel.add(new NumberButton("1"), 8); keyPanel.add(new NumberButton("2"), 9); keyPanel.add(new NumberButton("3"), 10); keyPanel.add(new CalcButton("-"), 11); keyPanel.add(new NumberButton("0"), 12); keyPanel.add(new NumberButton("."), 13); keyPanel.add(new CalcButton("+"), 14); keyPanel.add(new CalcButton("="), 15); contentPane.add(new ClearButton(), BorderLayout.SOUTH);//Cボタンを配置する this.setVisible(true); } /* テキストフィールドに引数の文字列をつなげる */ public void appendResult(String c) { if (!afterCalc) //演算子ボタンを押した直後でないなら result.setText(result.getText() + c); //押したボタンの名前をつなげる else { result.setText(c); //押したボタンの文字列だけを設定する(いったんクリアしたかに見える) afterCalc = false; } } /* 数字を入力するボタンの定義 */ public class NumberButton extends JButton implements ActionListener { private static final long serialVersionUID = 1L; public NumberButton(String keyTop) { super(keyTop); //JButtonクラスのコンストラクタを呼び出す this.addActionListener(this); //このボタンにアクションイベントのリスナを設定 } public void actionPerformed(ActionEvent evt) { String keyNumber = this.getText(); //ボタンの名前を取り出す appendResult(keyNumber); //ボタンの名前をテキストフィールドにつなげる } } /* 演算子ボタンを定義 */ public class CalcButton extends JButton implements ActionListener { private static final long serialVersionUID = 1L; public CalcButton(String op) { super(op); this.addActionListener(this); } public void actionPerformed(ActionEvent e) { if (isStacked) { //以前に演算子ボタンが押されたのなら計算結果を出す double resultValue = (Double.valueOf(result.getText())) .doubleValue(); if (currentOp.equals("+")) //演算子に応じて計算する stackedValue += resultValue; else if (currentOp.equals("-")) stackedValue -= resultValue; else if (currentOp.equals("×")) stackedValue *= resultValue; else if (currentOp.equals("÷")) stackedValue /= resultValue; result.setText(String.valueOf(stackedValue)); //計算結果をテキストフィールドに設定 } currentOp = this.getText(); //ボタン名から押されたボタンの演算子を取り出す stackedValue = (Double.valueOf(result.getText())).doubleValue(); afterCalc = true; if (currentOp.equals("=")) isStacked = false; else isStacked = true; } } /* クリアボタンの定義 */ public class ClearButton extends JButton implements ActionListener { private static final long serialVersionUID = 1L; public ClearButton() { super("C"); this.addActionListener(this); } public void actionPerformed(ActionEvent evt) { stackedValue = 0.0; afterCalc = false; isStacked = false; result.setText(""); } } }

noname#173931
質問者

お礼

お礼が遅れてしまいもうしわけありません。 回答していただきありがとうございます。 電卓部分のコードを載せていただきありがとうございます。 電卓本体部分はできているので、 表示桁以下の数値について おもに末尾から先頭方向へ'0'が続く場合の切り取りについて 教えていただければと思います ですが、貴重な時間をさいての回答、ありがとうございました。

関連するQ&A

  • java 電卓 平方根

    こんにちは。趣味でプログラミングをしているものです。 さっそくですが質問させていただきます。 Java で文具店で1000円くらいで売っているような電卓を再現 しようとしているのですが 平方根のボタンを押したときの処理でつまづいています。 3 を入力して平方根のボタンを押すと以下のサイトに表示されている限りにおいては 同じ数値になります。 http://ja.wikipedia.org/wiki/3%E3%81%AE%E5%B9%B3%E6%96%B9%E6%A0%B9 ここで質問の内容について説明させていただきます。 Windows に標準で付属している電卓では 0.5 を入力して平方根のボタンを押し続けると 最後には 1 が表示されます。 ですが、以下に示す自分のコードだと 0.99999999998 と表示されてその後 平方根のボタンを押し続けても同じ結果になります。 0.99999999998 で収束しているのだと思いますが、 (自分の作った電卓では小数点以外の数字は12個表示されるようになっています。) 1 に収束するようにするには、 以下に示す メソッドsqrt 内の計算部分の 割り算のスケールの指定とかを変えれば うまくいくのでしょうか? ----------------------------------------------- 平方根のボタンを押したときの処理です。 case CalculatorEvent.TYPE_SQRT : if( negativeflag ) { if( ! display.showBigMinus ) showNumString = showNumString.substring( 1 ); } result = sqrt( new BigDecimal( showNumString ) ); //test statement System.out.println( "from 1446 : " + result.toString() ); result = result.setScale( 32, RoundingMode.HALF_UP ); showNumString = result.toString(); //test statement; System.out.println( "sqrt result : " + showNumString ); // . . . . //以下おもに端数を表示桁数に丸めて、 //負の値の平方根を求めたときは //絶対値の平方根を求めて表示 // エラーであるマークも表示 // 呼び出し元に例外を投げる // 呼び出した側で例外を受け取ると // 電卓のボタンを入力できないようにする ----------------------------------------------- 上記コード test statement は以下の出力結果になると 以後 平方根のボタンを押しても同じ結果が出力されます。 from 1446 : 0.9999999999899999999999499999999994999999999937499999999125000000078125 sqrt result : 0.99999999998999999999995000000000 ------------------------------------------------ 上記コード中のメソッド sqrt です。 private BigDecimal sqrt( BigDecimal value ) { BigDecimal two = new BigDecimal( "2" ); BigDecimal x = value.divide( two ); BigDecimal last_x = BigDecimal.ZERO; BigDecimal gap = x.subtract( last_x ); BigDecimal range = BigDecimal.ONE.movePointLeft( 64 ); BigDecimal t; while( gap.compareTo(range) > 0 ) { last_x = new BigDecimal( x.toString() ); //t = value.divide( x, 64, BigDecimal.ROUND_DOWN ); //test statement t = value.divide( x, 64, RoundingMode.HALF_EVEN ); // x = x.add( t ).divide( two ); gap = x.subtract( last_x ).abs(); } return x; } ----------------------------------------------- 長文になりもうしわけありませんが、 ごぞんじのかた、教えていただけないでしょうか? よろしくお願いします。

    • ベストアンサー
    • Java
  • 平方根 ニュートン法について

    こんにちは。趣味でプログラミングをしているものです。 さっそくですが、質問させていただきます。 Javaで文具店などで1000円くらいで市販されている 電卓を再現しようとしているのですが、 質問させていただきたいのは、 平方根の計算についてです。 -------------------------------------------- まずは以下のメソッドのコードを見ていただきたいのですが・・・ このメソッドを用いて3の平方根を求めてみました。 private static BigDecimal sqrt( BigDecimal value ) { BigDecimal two = new BigDecimal( "2" ); BigDecimal x = value.divide( two ); BigDecimal last_x = BigDecimal.ZERO; BigDecimal gap = x.subtract( last_x ); BigDecimal range = BigDecimal.ONE.movePointLeft( 11 );//(a) //int cnt = 0;//(b) BigDecimal t; while( gap.compareTo(range) > 0 )//(c) //while( cnt < 20 )//(d) { last_x = new BigDecimal( x.toString() ); t = value.divide( x, 64, BigDecimal.ROUND_DOWN ); x = x.add( t ).divide( two ); gap = x.subtract( last_x );//(e) //cnt ++; //(f) } return x; } (a)(c)(e) を用いて実行すると 1.732142857142857142857・・・ と小数部分の142857 が循環する値になりました。 (a)(c)(e) をコメントアウトして (b)(d)(f) を用いて実行すると 1.732050807568877293527446341505872366942805253 810380628055806979425806427001953125 とwikipedia の「3の平方根」の記事の値と 記述されている範囲では同じ値が得られました。 -------------------------------------------- そこで質問なのですが、 (1) (a) (c) (e) を用いた場合には、正しい値を得られないのでしょうか? 条件に設定する値などを変えてもだめなのでしょうか? (2) 自分が作っている電卓では12桁の表示を予定しているのですが その場合、メソッド sqrt ないの cnt は while ループ内で いくつまで、インクリメントすればよいのでしょうか? (3) インターネットで調べたこのアルゴリズムは 「ニュートン法」だそうですが、 y = x^2 - C の グラフ、接線などを書いてみて ある程度理解できたのですが、 http://cpplover.blogspot.jp/2010/11/blog-post_20.html 上記サイトではこのアルゴリズムは バビロニア人の方法(Babylonian method) というものだそうですが、 バビロニア人は二次関数の微分はわかっていた、 ということでしょうか? -------------------------------------------- ご存知のかた、教えていただけないでしょうか? よろしくお願いします。

    • ベストアンサー
    • Java
  • 関数の極限の問題ですが

    解けないのでご教授お願いします。 lim[x→-∞]{(sqrt(x^2+x+1))-(sqrt(x^2-x+1))}です(sqrtは平方根) よろしくお願いします。

  • 積分できない!?

    こんにちは、 積分を習っているんですが、なかなか解けません! 助けてください! 問題は Integral dx/sqrt(37+2x+x^2)です ちなみにSqrtは平方根です。 よろしくお願いします

  • 改善すべき点を教えてください。

    趣味で最近Cを始めたのですが、ある本で「0を除く2種類の数字のみで構成された平方数」は、81619の二乗(6661661161)より大きいものはないらしい。 と書かれていたので、確かめたくなり色々調べながらプログラミングしてみました。 なんとか動くようになったのですが、いまいちスピードが遅いように感じるのです。 そこで、こうすればスピードを速くできる、ここが不自然な書き方になっているなど、どこか改善すべき点があれば教えて欲しく質問しました。 あと、char型からint型に数字を変換する時に恐らく不自然な方法でやっているので、正規の方法がありましたらそれも教えていただけると助かります。 よろしくおねがいします。 ここから――――――――――――――――――――――― #include <stdio.h> #include <string.h> int main(void){   double i;    //平方根   int m;    //整数(for用)   double x;  //平方数   char str[100];  //文字列(途中作業用)   int mono[100];  //1桁の数字(途中作業用)   int len;  //桁数   int num;  //二つ目の数の置場      for( i=1; i<=10000000000; i++){     x=i*i;              //二乗     sprintf(str,"%.0f",x);      //文字列に平方数を変換     len=strlen(str);         //桁数を求める          if(len<=1)       goto PRINT;          //平方数が一桁ならPRINTへ          for( m=0; m<len; m++){       mono[m]=str[m]-48;      //一桁ずつint型に収納+実際の数に調整。     }          m=(int)i;     if( m%2000000==0)       printf("i=%32.0f:ok - ",i);  //進行状況          for( m=0; m<len; m++)       if( mono[m]==0)         goto OUT;         //0が含まれていたらOUTへ     for( m=1; m<len; m++){       if( mono[m]==mono[0])         goto WHENSAME;      //mono[0]と同じ数字だったらWHENSAMEへ       num=m;            //違う数字の一回目の登場場所をnumに代入       break;            // →脱出       WHENSAME:           //ラベル WHENSAME     }     for( m=num+1; m<len; m++){       if( mono[m]==mono[0]);       else if( mono[m]==mono[num]);       else         goto OUT;       }     PRINT:              //ラベル PRINT     printf("%5.0f => %26.0f\n", i, x);     OUT:               //ラベル OUT   }   return 0; }

  • 特殊関数の定積分に関して質問です.

    exp(-s*sqrt(x^2+a^2)*x*J0(b*x)/sqrt(x^2+a^2)の0から∞までの半無限区間の積分が,なぜexp(-a*sqrt(s^2+b^2))/sqrt(s^2+b^2)になるのかわかりません. この証明の仕方を教えてください.ここで,J0(x)は0次第1種ベッセル関数,sqrt(x)はxの平方根です.

  • コマンドライン引数 java

    学校で、2進数表記された文字列number1、number2…numberNを数値に変換し、合計を算出し、2進数表記の文字列に変換した結果を出力するプログラムを組む課題が出ました。 java Lesson06 number1 number2 … numberN の形式で受け取ったコマンドライン引数を元に、処理を行います。 ※number1からnumberNは、全て0か1のみで構成されている文字列 * 文字列の加算 * System.outまたはSystem.errのprint系メソッドで、Stringの値を受け取るもの以外 * Integerなどのラッパークラス * DecimalFormatなどの書式変換クラス 上記の機能は使ってはいけません。 ---- class Lesson{  public static void main(String args[]){   int sum;   for(int i = 1; i < args.length; i ++) {    int len = strlen(args[i]);//※    for(int j = 0; j < len; j ++) {     if(args[i][len - j - 1] == "1") {//※      sum = pow(2, j) + sum;//※     }    }   }  } } ---- とりあえず、与えられた二進数を計算する部分まで作ってみたのですが、※の部分でエラーが出てしまいます。 コマンドライン引数もよく分からなくて困っているので、教えていただければ助かります。 以上よろしくお願いいたします。

    • ベストアンサー
    • Java
  • Javaの判定処理について

    いつもお世話になっております。 以下のJavaのコードで、 ☆の部分のif文が何を実施しているのか 分からないのですが、 ご存知の方がいられましたら ご教授をいただけますでしょうか。 【コード】 String value = "あいうえお12345"; int length = value.length(); for (int i = 0; i < length; i++) { char c = value.charAt(i); if ((c & ~0x7f) != 0) { ←☆ 処理1 } }

    • ベストアンサー
    • Java
  • javaのプログラミングについての質問です

    javaのプログラミングについての質問です 任意の複数の数値を入れたファイルを読み取りその数値の場所から次の数値まで線を描画するプログラミングを作成しました ここから発展問題としてタートルグラフィックスを 描画するプログラムを50歩進み右に90度曲がることを4度繰り返すという条件で作ってみようと思ったのですが上手くコンパイルが通りません 取りあえず分かっているのは (100.cos45,100.sin45)で90°曲がる repeat 4,forward 50right 90 end 0 だけです もし分かる方がいらっしゃいましたらご返答宜しくお願いします import java.awt.*; import java.awt.event.*; import java.io.*; public class mondai{ int x[] = new int[100]; int y[] = new int[100]; int len = 0; public static void main(String[] args){ new mondai(args[0]); } public mondai(String mondai2){ ReadFile rf = new ReadFile(mondai2); String line; while( (line = rf.gets()) != null) { String[] date = line.split(","); if(date.length == 2){ x[len] = Integer.parseInt(date[0]); System.out.println(date[0]); y[len]= Integer.parseInt(date[1]); System.out.println(date[1]); len++; } } Frame f = new Frame(); f.setTitle("Line"); f.setSize(640,480); f.setLayout(null); f.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); }}); DrawArea da = new DrawArea(); da.setBounds(0,0,640,480); f.add(da); f.setVisible(true); } private class DrawArea extends Canvas{ public void paint(Graphics g){ for(int i=0;i<len-1;i++) g.drawLine(x[i],y[i],x[i+1],y[i+1]); } } private class ReadFile{ FileInputStream fis; InputStreamReader isr; BufferedReader br; public ReadFile(String filename){ try{ fis = new FileInputStream(filename); isr = new InputStreamReader(fis); br = new BufferedReader(isr); }catch(Exception e){ e.printStackTrace(); } } public String gets(){ String line = ""; try{ line = br.readLine(); }catch(Exception e){ e.printStackTrace(); } return line; } } }

  • JavaでXORによる暗号化

    JavaでXORによる暗号化について調べていたら下記URLのサイトを見つけました。 http://www.eeb.co.jp/2007/07/_10_1.html そこでサンプルにあった下記プログラムをvalue と key を変えて実行してみたところ value の中の「は」、「で」がうまく復元されず文字化けしてしまいました。 どこが悪いのかよくわからないのですがお分かりになられる方がいらっしゃいましたら 教えていただけますでしょうか。 public class XorTest { //================================================== // メイン //================================================== public static void main(String[] args) { String value = "abcd本日はお日柄もよろしいようで"; String key = "1"; // 暗号化前出力 print("暗号化前", value); // 暗号化 byte[] byteEncodeArray = encode(value.getBytes(), key); value = new String(byteEncodeArray); // 暗号化後出力 print("暗号化後", value); // 復元 byte[] byteDecodeArray = decode(value.getBytes(), key); value = new String(byteDecodeArray); // 復元後出力 print("復元後", value); } //================================================== // 暗号化 //================================================== private static byte[] encode(byte[] src, String key) { byte[] byteKeyArray = new byte[0]; byte[] byteEncArray = new byte[src.length]; // キーの文字列を変換する文字列をカバーするまで繰り返す while(byteKeyArray.length < src.length) { byteKeyArray = (new String(byteKeyArray) + key).getBytes(); } // 変換 for (int i = 0; i < src.length; i++) { byteEncArray[i] = (byte)(src[i]^byteKeyArray[i]); } return byteEncArray; } //================================================== // 復元 //================================================== private static byte[] decode(byte[] src, String key) { return encode(src, key); } //================================================== // ダンプ文字列取得 //================================================== private static String getDump16(byte[] value) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < value.length; i++) { String hex = Integer.toHexString((int)value[i] & 255); // 4桁に揃える hex = "0000" + hex; hex = hex.substring(hex.length() - 4, hex.length()); // バッファに追加(空白区切り、10桁ずつ改行) buf.append(hex + (i % 10 == 9?System.getProperty("line.separator"):" ")); } return buf.toString().trim(); } private static void print(String title, String value) { System.out.println("【 " + title + " 】"); System.out.println("-----------------------------"); System.out.println(value); System.out.println(getDump16(value.getBytes())); System.out.println(); System.out.println(); } }

    • ベストアンサー
    • Java

専門家に質問してみよう