Get reduced fraction from BigDecimal
我正在做一些非常精确的十进制计算,最后我将其转换为减少的分数。小数位数需要精确到96个小数位数。
由于精度非常重要,因此我使用BigDecimal和BigInteger。
BigDecimal的计算总是返回正确的十进制值,但是在某些情况下,我无法将此十进制转换为小数的函数
假设我有一个BigDecimal d
1 | d.toString() = 32.222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223 |
当我的函数试图将其转换为分数时,它输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Decimal from BigDecimal is: 32.222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223 // Run the BigDecimal into getFraction Denominator before reducing: 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Numerator before reducing: 32222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223 // Reduced fraction turns into: -1/0 // But should output 290/9 |
这是我的将小数减为小数的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | static int[] getFraction(BigDecimal x) { BigDecimal x1 = x.stripTrailingZeros(); //System.out.println(x.toString() +" stripped from zeroes"); //System.out.println(x1.scale()); // If scale is 0 or under we got a whole number fraction something/1 if(x1.scale() <= 0) { //System.out.println("Whole number"); int[] rf = { x.intValue(), 1 }; return rf; } // If the decimal is if(x.compareTo(BigDecimal.ZERO) < 0) { // Add"-" to fraction when printing from main function // Flip boolean to indicate negative decimal number negative = true; // Flip the BigDecimal x = x.negate(); // Perform same function on flipped return getFraction(x); } // Split BigDecimal into the intval and fractional val as strings String[] parts = x.toString().split("\\\\."); // Get starting numerator and denominator BigDecimal denominator = BigDecimal.TEN.pow(parts[1].length()); System.out.println("Denominator :" + denominator.toString()); BigDecimal numerator = (new BigDecimal(parts[0]).multiply(denominator)).add(new BigDecimal(parts[1])); System.out.println("Numerator :" + numerator.toString()); // Now we reduce return reduceFraction(numerator.intValue(), denominator.intValue()); } static int[] reduceFraction(int numerator, int denominator) { // First find gcd int gcd = BigInteger.valueOf(numerator).gcd(BigInteger.valueOf(denominator)).intValue(); //System.out.println(gcd); // Then divide numerator and denominator by gcd int[] reduced = { numerator / gcd, denominator / gcd }; // Return the fraction return reduced; } |
如果有人能澄清我是否犯了任何错误,我将不胜感激!
**更新**
更改了reduceFraction函数:
现在返回一个String []而不是int []
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | static String[] reduceFraction(BigDecimal numerator, BigDecimal denominator) { // First find gcd BigInteger nu = new BigInteger(numerator.toString()); BigInteger de = new BigInteger(denominator.toString()); BigInteger gcd = nu.gcd(de); // Then divide numerator and denominator by gcd nu = nu.divide(gcd); de = de.divide(gcd); String[] reduced = { nu.toString(), de.toString() }; // Return the fraction return reduced; } |
getFraction返回:
1 2 | // Now we reduce, send BigDecimals for numerator and denominator return reduceFraction(num, den); |
而不是
1 2 | // Now we reduce return reduceFraction(numerator.intValue(), denominator.intValue()); |
仍然从函数得到错误答案
输出分数现在为
1 2 3 4 5 | // Gcd value gcd = 1 // Fraction is then: 32222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223/1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 |
1 2 3 4 5 | //gcd Value should be: gcd = 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 // Whit this gcd the fraction reduces to: 290/9 |
1 2 | // Now we reduce return reduceFraction(numerator.intValue(), denominator.intValue()); |
好吧,在这种情况下这一定会失败,因为这里的分子或分母都不适合
分子变为-1908874353,对它们调用
在将它们转换为
您似乎正在使这项工作变得更加困难。这是我最初的尝试:
1 2 3 4 5 6 7 8 9 10 11 12 | public static BigInteger[] toRational(BigDecimal decimal) { int scale = decimal.scale(); if (scale <= 0) { return new BigInteger[]{decimal.toBigInteger(), BigInteger.ONE}; } else { BigInteger denominator = BigInteger.TEN.pow(scale); BigInteger numerator = decimal.unscaledValue(); BigInteger d = numerator.gcd(denominator); return new BigInteger[]{numerator.divide(d), denominator.divide(d)}; } } |
有理数始终以最低的条款返回。请注意,如果