【问题标题】:Truncating float to the two first non-zero decimal digits将浮点数截断为前两个非零十进制数字
【发布时间】:2016-07-15 18:50:26
【问题描述】:

我想将 Java 中的浮点数截断为前两个非零十进制数字。例如,0.0001340.00013,或 11.0040111.0040

我能想到的唯一解决方案是去掉整数部分,然后乘以 10,直到得到一个大于或等于 10 的数字。然后将原始浮点数截断为 number of multiplications 十进制数字。

但我可能不得不经常执行此操作,因此我正在寻找更快的解决方案。

我的测试代码:

public static String truncateTo2NonZero(double f) {
    int integral = (int)f;
    double decimal = f - integral;
    int digits = 0;

    while (decimal < 10) {
        decimal *= 10;
        digits++;
    }

    double ret = (int)decimal / Math.pow(10, digits);
    ret += integral;

    return Double.toString(ret);
}

public static void main(String args[]) {
    final int TESTS = 1000000;
    double[] floats = new double[TESTS];

    Random random = new Random();
    for (int i = 0; i < TESTS; ++i) {
        int zeros = random.nextInt(6) + 3; // divide by 10^zeros
        double digits = random.nextInt(100) + 100; // 3 last digits
        floats[i] = digits / Math.pow(10,zeros) + random.nextInt(20) + 1;
    }

    long startTime = System.nanoTime();
    for (int i = 0; i < TESTS; ++i)
        truncateTo2NonZero(floats[i]);
    long endTime = System.nanoTime();

    long duration = endTime - startTime;
    System.out.println(duration / 1000000); // in milliseconds
}

我使用的是 64 位 Windows 7 家庭高级版。 java -version的输出:

java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)

【问题讨论】:

  • 这看起来不像是那些骗子。这里的 OP 希望有一个动态的小数位数,即保留前两个非零小数位数。
  • @copeg 不重复。就像图纳基说的那样。我认为从我给出的两个例子中可以很清楚地看到。
  • "floating point" "decimal digits" 这两个短语不应该出现在同一个句子中。你应该使用BigDecimal

标签: java floating-point


【解决方案1】:

当您说要“截断”时,这听起来像是一种显示格式。话虽如此,花车对此并不友好。 BigDecimals 是。这应该给你一个开始,当然需要错误检查。

static String roundToLastTwoDecimalDigits(float f) {
    // split whole number and decimals
    String[] floatParts = new BigDecimal(f).toPlainString().split("\\.");

    int wholeNumberPortion = Integer.parseInt(floatParts[0]);

    // count zeroes
    String decimalPortion = floatParts[1];
    int numDecimalPlaces = 0;
    while (decimalPortion.charAt(numDecimalPlaces) == '0')
        numDecimalPlaces++;

    // get 3 digits to round
    String toRound = decimalPortion.substring(numDecimalPlaces,
            numDecimalPlaces + 3);

    int decimalForRounding = Math.round(Float.parseFloat(toRound) / 10);

    StringBuilder sb = new StringBuilder();

    sb.append(wholeNumberPortion);
    sb.append(".");
    for (int i = 0; i < numDecimalPlaces; i++)
        sb.append("0");
    sb.append(decimalForRounding);

    return sb.toString();
}

【讨论】:

  • 刚刚测试过,这个比较慢。 3703 毫秒,而我的方式是 538 毫秒,500k 随机浮点数。
  • @devil0150 BigDecimal 并不是要快,而是要正确。
  • @devil0150 你能分享你的代码吗?我正在考虑一种算法,很像 Compass 的算法,但计算强度较低。但是,为了确保我们将苹果与苹果进行比较,请分享您的代码以考虑生成随机数的时间和方法。另外,请告诉我们您的机器/JVM 规格。
猜你喜欢
  • 1970-01-01
  • 2017-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-01
  • 2011-02-12
  • 1970-01-01
相关资源
最近更新 更多