Rational numbers (numbers that can be expressed in the form of integers / integers) can always be expressed as either finite decimals or recurring decimals. On the contrary, finite decimals and recurring decimals can always be expressed in the form of rational numbers.
Example 3/4 = 0.75 1/7 = 0.142857142857... = 0.(142857) (The circulating part of a recurring decimal is called a recurring node, and it is represented by dots on the first and last numbers of the recurring node. Recurring nodes are shown in parentheses. )
I wanted to represent an arbitrary rational number with a decimal number that does not cut off in the middle, so I created a class that represents a rational number, As one of the methods, I created a method that "puts out a decimal notation that can be expressed as a recurring clause from a rational number". Also, as one of the factory methods, I created a method that receives a decimal character string including a recurring clause expression and converts it into a rational number.
The fields of the rational number class are molecule: molecule, long type denominator: denominator, long type And said. In addition, the sign elements are unified and the numerator has them, and they are invariant classes in the form of irreducible fractions. If it is an integer, I decided to have it in the form of 1 in the denominator.
Convert rational numbers to decimals
public String toDecimalString() {
//If it is an integer, it will be displayed as it is
if (denominator == 1L)
return String.valueOf(molecule);
//Divide in the manner of long division. First, take out the integer part
LinkedHashMap<Long, Long> restAndDigit = new LinkedHashMap<>();
long integer = Math.abs(molecule) / denominator;
long remind = Math.abs(molecule) % denominator;
//Repeat the division until the same remainder as the above-mentioned remainder appears or is divisible.
while (!restAndDigit.containsKey(remind) && remind != 0L) {
long r = remind * 10L;
restAndDigit.put(remind, r / denominator);
remind = r % denominator;
}
StringBuilder builder = new StringBuilder();
if (molecule < 0L)
builder.append('-');
builder.append(integer).append('.');
//If it is divisible, display all digits side by side
if (remind == 0L) {
restAndDigit.values().forEach(builder::append);
return builder.toString();
}
Iterator<Map.Entry<Long, Long>> iterator = restAndDigit.entrySet().iterator();
Map.Entry<Long, Long> temp;
while (!(temp = iterator.next()).getKey().equals(remind)) {
builder.append(temp.getValue());
}
builder.append('(').append(temp.getValue());
iterator.forEachRemaining(e -> builder.append(e.getValue()));
return builder.append(')').toString();
}
Decimal notation to rational numbers
public static Fraction2 parseDecimal(String str) {
Matcher matcher = Pattern.compile("(-?\\d+\\.\\d*)(\\(\\d+\\))?").matcher(str);
if (!matcher.matches())
throw new NumberFormatException("Illegal input : " + str);
BigDecimal decimal = new BigDecimal(matcher.group(1));
if (matcher.group(2) == null)
return fromDecimal(decimal);
BigInteger m1 = decimal.unscaledValue();
BigInteger d1 = TEN.pow(decimal.scale());
BigDecimal decimal2 = new BigDecimal(matcher.group().replaceAll("[\\(\\)]", ""));
BigInteger m2 = decimal2.unscaledValue();
BigInteger d2 = TEN.pow(decimal2.scale());
//Another method to make a rational number using BigInteger
return fromBigInteger(m2.subtract(m1), d2.subtract(d1));
}
Originally, the denominator numerator was made with BigInteger and left unattended, but I rewrote it to long thinking that "a large number will not come to the denominator numerator", but I am worried about overflow due to addition and multiplication. I remembered that I was using BigInteger because it was troublesome to start orz