确保十进制数的字符串 repr 总是 n 个字符长

Making sure a string repr of decimal number is always n characters long

我需要确保所有十进制数字的长度始终最多为 15 个字符(包括点),同时尽可能保持精度。因此,它最多必须是 15 个字符,包括“.”。 "E" 用于科学记数法和“-”。

我想的是大数用科学记数法,小数用四舍五入。

例如,对于 1234567891234567.123456789,我会使用科学记数法,但对于 0.123456789123456789,我会四舍五入。

我寻找 java 可以为我执行此操作的库,但我找不到任何可以让我指定表示的字符总数的库。

感谢任何建议或指点。

编辑:更多想法 - 使用 24000E-18 可以毫无损失地表示诸如 0.000000000000024 之类的数字。虽然例如 0.123456789123424 必须遭受一些损失,这当然会使编写任何类型的简单分支算法变得更加困难。

EDIT2:我们用于传输数据的格式是字母数字,并且将数据总共限制为 15 个字符。我必须编写代码来满足格式,以便可以在不触发格式错误的情况下传输数据,同时仍将最大精度保持在限制范围内。

EDIT3:我正在使用它来测试我的功能,但到目前为止,在某些情况下一切都失败了:

  Random rnd = new Random();
  double n = 100000 + rnd.nextDouble() * 900000;
  String res;
  double rangeMin = -123456789123456D;
  double rangeMax = 123456789123456D;
  String val;
  for (int i=1;i<=1000;i++) {
    n = rangeMin + (rangeMax - rangeMin) * rnd.nextDouble();
    val = Double.toString(n);
    res = shorteningFunction(val);
    System.out.println(val + " " + val.length() + " " + res + " " + res.length());
  }

我不想发布不起作用的代码,所以我删除了混乱的代码。

这是伪代码中的思想:

  1. 将其转换为字符串。
  2. 检查长度
  3. 循环:
    • 如果长度太长:
    • 删除预测。
    • 将其转换为字符串。
    • 检查长度。
  4. Return

可以利用BigDecimal,对于整数部分BigInteger

/**
 * @param num number representation.
 * @param max the maximal length the result should have.
 * @return
 */
public static String truncateNumber(String num, int max) {
    num = num.replaceFirst("\.0*$", "");
    BigDecimal x = new BigDecimal(num);

    // Large numbers - integral part
    String bigI = x.toBigInteger().toString();
    if (bigI.length() > max) {
        int expon10 = bigI.length() - max - 1; // - 1 for E

        // Digits after E:
        if (expon10 == 0) {
            ++expon10;
        } else {
            for (int p = expon10; p > 0; ++p) {
                ++expon10;
                p /= 10;
            }
        }
        x = x.movePointLeft(expon10);
        String plain = x.toPlainString().substring(0, max - 1 - expon10);
        return plain + "E" + expon10;
    }

    // Tiny numbers - 0.000 (as E-1 already requires 3 positions)
    String reprP = x.toPlainString();
    if (reprP.startsWith("-0.00")) {
        return truncateNumber(num.substring(1), max - 1);
    } else if (reprP.startsWith("0.00")) {
        String reprE = x.toEngineeringString(); // Does most work.
        int epos = reprE.indexOf('E');
        String mantissa = reprE.substring(0, epos);
        String exp = reprE.substring(epos);
        return mantissa.substring(0, Math.min(epos, max - exp.length())) + exp;
    }

    // Normal range - assumed in format 123.456, integral part in range
    String simple = x.toPlainString();
    if (simple.length() > max) {
        simple = simple.substring(0, max).replaceFirst("\.0*$", "");
    }
    return simple;
}

这可能会写得更好,以 \.0* 结尾的子字符串,尤其是 toPlainString 等的一些重复用法。 max太小也是有害的。

是否num可能以科学/工程符号给出也开放。