4

だから私がやろうとしているのは、double を有理数に変換することです。小数点以下の桁数を確認し、たとえば、数値 123.456 を 123456 / 1000 として保存したいと考えています。

public Rational(double d){      
    String s = String.valueOf(d);
    int digitsDec = s.length() - 1 - s.indexOf('.');        

    for(int i = 0; i < digitsDec; i++){
        d *= 10;
    }

    System.out.println((int)d); //checking purposes
}   

ただし、数値 123.456 の場合、丸めエラーが発生し、結果は 123455 になります。これを BigDecimal で修正することは可能だと思いますが、機能させることはできません。また、有理数を計算したら、パラメーター (int 分子、int 分母) を使用して別のコンストラクターを呼び出したいのですが、println が現在ある行でコンストラクターを呼び出すことは明らかにできません。どうすればいいですか?

4

5 に答える 5

6

質問の最初の部分では、Java は .6 を .5999999 (繰り返し) として格納しています。次の出力を参照してください。

(after first multiply): d=1234.56
(after second multiply): d=12345.599999999999
(after third multiply): d=123455.99999999999

1 つの修正は、ループが終了した直後に d = Math.round(d) を使用することです。

public class Rational {

     private int num, denom;

     public Rational(double d) {
          String s = String.valueOf(d);
          int digitsDec = s.length() - 1 - s.indexOf('.');        

          int denom = 1;
          for(int i = 0; i < digitsDec; i++){
             d *= 10;
             denom *= 10;
          }
          int num = (int) Math.round(d);

          this.num = num; this.denom = denom;
     }

     public Rational(int num, int denom) {
          this.num = num; this.denom = denom;
     }

     public String toString() {
          return String.valueOf(num) + "/" + String.valueOf(denom);
     }

     public static void main(String[] args) {
          System.out.println(new Rational(123.456));
     }
}

動作します - 試してみてください。

あなたの質問の2番目の部分について...

最初のコンストラクターから 2 番目のコンストラクターを呼び出すには、「this」キーワードを使用できます。

this(num, denom)

しかし、それはコンストラクターの最初の行でなければなりません... ここでは意味がありません (最初にいくつかの計算を行う必要があります)。だから私はそれをやろうとはしません。

于 2012-12-23T19:51:33.533 に答える
3

このコードはやり過ぎかもしれませんが、発生している丸め誤差を処理し、小数の繰り返しも処理します (4.99999999999999 は 5 になり、0.33333333333333333333 は 1/3 になります)。

public static Rational toRational(double number){
return toRational(number, 8);
}

public static Rational toRational(double number, int largestRightOfDecimal){

long sign = 1;
if(number < 0){
    number = -number;
    sign = -1;
}

final long SECOND_MULTIPLIER_MAX = (long)Math.pow(10, largestRightOfDecimal - 1);
final long FIRST_MULTIPLIER_MAX = SECOND_MULTIPLIER_MAX * 10L;
final double ERROR = Math.pow(10, -largestRightOfDecimal - 1);
long firstMultiplier = 1;
long secondMultiplier = 1;
boolean notIntOrIrrational = false;
long truncatedNumber = (long)number;
Rational rationalNumber = new Rational((long)(sign * number * FIRST_MULTIPLIER_MAX), FIRST_MULTIPLIER_MAX);

double error = number - truncatedNumber;
while( (error >= ERROR) && (firstMultiplier <= FIRST_MULTIPLIER_MAX)){
    secondMultiplier = 1;
    firstMultiplier *= 10;
    while( (secondMultiplier <= SECOND_MULTIPLIER_MAX) && (secondMultiplier < firstMultiplier) ){
        double difference = (number * firstMultiplier) - (number * secondMultiplier);
        truncatedNumber = (long)difference;
        error = difference - truncatedNumber;
        if(error < ERROR){
            notIntOrIrrational = true;
            break;
        }
        secondMultiplier *= 10;
    }
}

if(notIntOrIrrational){
    rationalNumber = new Rational(sign * truncatedNumber, firstMultiplier - secondMultiplier);
}
return rationalNumber;
}

これにより、次の結果が得られます (テスト ケースの結果はコメントとして表示されます)。

Rational.toRational(110.0/3.0); // 110/3
Rational.toRational(11.0/1000.0); // 11/1000
Rational.toRational(17357.0/33300.0); // 17357/33300
Rational.toRational(215.0/21.0); // 215/21
Rational.toRational(0.123123123123123123123123); // 41/333
Rational.toRational(145731.0/27100.0); // 145731/27100
Rational.toRational(Math.PI); // 62831853/20000000
Rational.toRational(62.0/63.0); // 62/63
Rational.toRational(24.0/25.0); // 24/25
Rational.toRational(-24.0/25.0); //-24/25
Rational.toRational(-0.25333333333333333333333); // -19/75
Rational.toRational(-4.9999999999999999999999); // -5
Rational.toRational(4.9999999999999999999999);  // 5
Rational.toRational(123.456); // 15432/125
于 2014-09-28T12:09:11.407 に答える
2

エレガントではありませんが、これはあなたが求めていることだと思います。

double a = 123.456;
String aString = Double.toString(a);        
String[] fraction = aString.split("\\.");

int denominator = (int)Math.pow(10, fraction[1].length());
int numerator = Integer.parseInt(fraction[0] + "" + fraction[1]);

System.out.println(numerator + "/" + denominator);
于 2012-12-23T20:55:23.270 に答える
0

試す

for(int i = 0; i <= digitsDec; i++){

}
于 2012-12-23T19:57:18.190 に答える