繁体   English   中英

使用 Java 以输入的精度递增浮点数

[英]Increment floating point numbers with the precision of the input with Java

我正在寻找以自己的精度递增浮点数的最优化且易于阅读的版本:

increment(1000) should return 1001
increment(100.1) should return 100.2
increment(0.1) should return 0.2
increment(0.01) should return 0.02
increment(0.001) should return 0.002
increment(0.0009) should return 0.0010
increment(0.000123) should return 0.000124
increment(increment(0.0009)) should return 0.002

它可以通过字符串操作来完成,但我不想将其转换为字符串并将其解析回双精度。

我使用字符串操作完成了以下操作:

public static double incrementWithMover(double value){
    DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
    df.setMaximumFractionDigits(340); //340 = DecimalFormat.DOUBLE_FRACTION_DIGITS
    String valueString = df.format(value);
    String[] splitted = valueString.split("\\.");

    StringBuilder mover = new StringBuilder();

    if(splitted.length == 2){ // Floating Decimals
        int precision = splitted[1].length();
        df.setMaximumFractionDigits(precision);
        mover = new StringBuilder("0.");
        for(int i =1; i<precision; i++){
            mover.append("0");
        }

        mover.append("1");
    }
    else{   // Non Floating Decimals
        mover = new StringBuilder("1");
    }


    double incremented = Double.parseDouble(valueString) + Double.parseDouble(mover.toString());
    return Double.parseDouble(df.format(incremented));
}

我正在尝试编写此方法,因为我正在检查不同的值并尝试将所有值以它们自己的精度递增一

编写这种incrementFloating方法的最佳方法是什么?

这可能对你有用。 从双打改为弦乐。

String[] vals = { "1000","1000.1", ".1", ".01", ".001", ".00123", ".0004" };
for (String v : vals) {
    System.out.printf("%s -> %s%n", v, incrementFloating(v));
}

印刷

1000 -> 1001
1000.1 -> 1000.2
.1 -> 0.2
.01 -> 0.02
.001 -> 0.002
.00123 -> 0.00124
.0004 -> 0.0005

方法声明


public static String incrementFloating(String v) {  
    BigDecimal b = new BigDecimal(v);
    BigDecimal increment =
            BigDecimal.valueOf(1).scaleByPowerOfTen(-b.scale());
    return b.add(increment).stripTrailingZeros().toString();
}

使用 Java 以输入的精度递增浮点数

这不是它的工作原理。

浮点数和双精度数并不像您显然认为的那样存储。

想象一下整个数轴。 从负无穷到正无穷。

这条线上有无数个 integer 值。 在任何 2 个 integer 值之间,也存在无限数量的值。

电脑不是魔法。 浮点数是 32 位,双精度数是 64 位。 根据基本数学,32 位最多只能区分 2^32 个数字,即大约 40 亿。

40 亿是路,远小于无穷大的 2 个数量级

那么是如何工作的呢? 好吧,大约有 40 亿个数字是“祝福”的。 这些数字可以用float表示,其他数字不能 比如 0.3就没有被祝福 0.3 根本不是浮点数系统中的数字。 它不存在。

那么,我该如何解释float x = 0.3; 工作,或者当你运行时会发生什么float x = 0.1 + 0.2; ?

好吧,float 和 double 操作会默默地转换为最近的祝福数字。

祝福数字的分布基于二进制(因此在十进制中它们没有任何特殊意义),并且分布不均。 例如,在接近 1.0 时,有远超过接近 100.0 的地方。

这意味着错误无处不在 您从根本上描述的操作在这里没有意义。 你不能用花车或双打做你想做的事。 时期。

Go 带字符串,或 go 带 BigDecimal。

如果您有兴趣,这里是 go:

BigDecimal bd = new BigDecimal(0.3);
System.out.println(bd);
> 0.299999999999999988897769753748434595763683319091796875

这不是我编的。 编写该代码并运行它。 那个不敬的数字是什么?

这是最接近 0.3 的祝福数字。

So, in double number systems, applying your algorithm, increment(0.3) would try to calculate 0.299999999999999988897769753748434595763683319091796876 , which isn't blessed, and the nearest blessed number to that is simply 0.299999999999999988897769753748434595763683319091796875 again, and the operation would do nothing.

没有意义。

Strings 或 BigDecimal,这是唯一的方法。 从这个意义上说,window 的效率更高,但除非您打算每秒运行此操作数百万次,否则您不会注意到。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM