如何格式化小数位数精度

时间:2019-01-10 13:10:54

标签: java

如何格式化小数位数精度,如下所示:

double d = 1/3返回0.3333333333333333,并在数学上 3 无限重复

d = ((double)3)/ (double)41;返回0.07317073170731707,并在此重复 07317

现在,要求格式化输出如下

0.3333333333333333的格式应为0.(3),重复3次。

类似地,0.07317073170731707应该格式化为0.(07317),重复 07317

我看过DecimalFormat类,但是我只能格式化许多精度。

public static void main(String[] args) {
        DecimalFormat formatter = new DecimalFormat("#0.'('##')'");

        double d = ((double)1)/ (double)3;
        System.out.println("formatted "+formatter.format(d));
        System.out.println(d);


        d = ((double)1)/ (double)2;
        System.out.println("formatted "+formatter.format(d));
        System.out.println(d);


        d = ((double)3)/ (double)41;
        System.out.println("formatted "+formatter.format(d));
        System.out.println(d);

    }

输出:

formatted 0.33()
0.3333333333333333
formatted 0.5()
0.5
formatted 0.07()
0.07317073170731707

Java 中是否有任何内置类可以实现相同目的?

3 个答案:

答案 0 :(得分:2)

正如注释中指出的那样,如果您只有一个String表示形式,那么就无法判断它实际上是否有重复的部分,或者精度是否不够高。

但是,从您的样本中看来,您似乎实际上是想找到分数的重复部分,而您知道分子和分母都是精确的整数。这不是一个太大的问题。例如,您可以查看https://codereview.stackexchange.com/questions/87522/decimal-expansion-of-a-rational-number

===更新===

我正在研究一个用分子和分母表示为BigIntegers的有理数的类(并假定尽可能地简化)。在那里,我实现了一种生成表示形式为十进制字符串的方法,并提出了以下内容:

public String toDecimalString() {

    var result = new StringBuilder();

    var remainders = new HashMap<BigInteger, Integer>();

    if(!isNonNegative()) result.append("-");
    var divAndRem = numerator.abs().divideAndRemainder(denominator);
    result.append(divAndRem[0].toString());

    if(isWholeNumber()) return result.toString();

    result.append(".");

    int currentPosition = result.length();
    remainders.put(divAndRem[1], currentPosition);

    while(!divAndRem[1].equals(BigInteger.ZERO)) {
        divAndRem = divAndRem[1].multiply(BigInteger.TEN).divideAndRemainder(denominator);
        result.append(divAndRem[0].toString());
        if(remainders.containsKey(divAndRem[1])) {
            int periodStart = remainders.get(divAndRem[1]);
            return result.substring(0, periodStart)+"["+result.substring(periodStart)+"]";
        }
        remainders.put(divAndRem[1], ++currentPosition);
    }

    return result.toString();

}

答案 1 :(得分:1)

不幸的是,我不知道这样的一类,也许数学家知道。问题在于无限表示的一部分变成了有限表示,并且必须用符号进行重复组的计算,而不是使用一些立即二进制数。 (也许是一个不错的学生项目。)

double有缺陷。一个人可以基于BigDecimal来创建自己的类,该类可以标识重复的小数并存储这样的“无限”数字。像π这样的许多无穷数仍然无法使用。

或者您可以使用(分子,分母)创建有理数类。

在极少数情况下,您可以通过切换数字基数来避免重复小数, 因为Integer / Long可以使用不同的基础,并且可以在此基础上构建:

0.1以3为基= 0.33333 ...以10为基

答案 2 :(得分:0)

您可以创建一种将简单重复考虑在内的方法,如下所示。

public static double reformatNumber(double number) {
  String s = String.valueOf(number);

  String[] split = s.split("\\.");

  String result = split[1].substring(0,8); // Length to consider
  String actualDigit = "";
  String lastDigit = "";
  int counter = 0;
  for (int i = 1; i <= result.length(); i++) {
    actualDigit = result.substring(i-1,i);
    if (actualDigit.equals(lastDigit)) {
      counter++;
    } else {
      counter = 0;
    }
    lastDigit = actualDigit;
    if (counter == 3) { // Number of repetitions in a row required
      result = result.substring(0,i-1);
    }
  }
  s = split[0]+"."+result;

  return Double.parseDouble(s);
}

如果要考虑重复两个或多个,只需修改最后一个方法即可一次保存两位数,就像这样。

public static double reformatNumber(double number) {
  String s = String.valueOf(number);

  String[] split = s.split("\\.");

  String result = split[1].substring(0,8);
  String actualDigit = "";
  String lastDigit = "";
  int counter = 0;
  for (int i = 1; i <= result.length(); i++) {
    actualDigit = result.substring(i-1,i);
    if (actualDigit.equals(lastDigit)) {
      counter++;
    } else if (i%4 == 0 && (actualDigit+lastDigit).equals(result.substring(i-4,i-2))) { 
      // Every four cycles checks if the last digit and the current one 
      // are equals to the last two digits before the last digit
      counter++;
    } else {
      counter = 0;
    }
    lastDigit = actualDigit;
    if (counter == 3) {
      result = result.substring(0,i-1);
      break;
    }
  }
  s = split[0]+"."+result;

  return Double.parseDouble(s);
}