【问题标题】:Strange double-to-string conversion奇怪的双字符串转换
【发布时间】:2012-06-26 14:15:19
【问题描述】:

我正在使用以下代码在我的一个活动中填充 Spinner...

    for( double i = 0; i < 10 ; i+=0.1 ) {
        rVoltsList.add( Double.toString( i ) );
    }
    Spinner rVoltsSpinner = (Spinner) findViewById( R.id.recloseVoltsSpinner );
    ArrayAdapter<String> rVoltsAdapter = new ArrayAdapter<String>( this, android.R.layout.simple_spinner_item, rVoltsList );
    rVoltsSpinner.setAdapter( rVoltsAdapter );

我假设这会给我一个如下列表:0.0、0.1、0.2、0.3、0.4 等等。 但是,这是我运行程序时列表的样子:

0.0
0.1
0.2
0.30000000000000000000000004
0.4
0.5
0.6
0.7
0.79999999999999999999
0.89999999999999999999
0.99999999999999999999
1.09999999999999999999
1.2
1.3
and this goes on until 9.99999999999999999998

有什么想法吗?

【问题讨论】:

标签: android double


【解决方案1】:

使用这个:

rVoltsList.add( String.format("%.1f", i) );

问题是Double.toString(i) 不会舍入。

奇怪的值是由于 0.1(以 10 为基数)在 Java 中没有像 double 那样的精确表示,所以每次将它添加到循环变量时,你添加的东西有点不同于你怎么想(如果你能原谅双关语的话)。

同样的舍入问题表明您不应该使用double 作为循环变量。你不太可能完全达到你的循环限制。我会重写你的循环如下:

for( int i = 0; i < 100 ; ++i ) {
    rVoltsList.add( String.format("%.1f", i / 10.0) );
}

【讨论】:

  • 这行得通,但我不明白....如果我只是在 i 的值上加 0.1,它是如何得到那些奇怪的值的?
  • @JuiCe - 问题是双精度数的算术通常不准确。特别是,(以 10 为底)值 0.1 没有二进制的精确表示。因此,总和的最后一位或两位将关闭。将 0.1 添加到数字上的次数越多,这种舍入误差通常会变得更糟。
  • @JuiCe - 由于浮点计算中存在相同的舍入误差问题,您应该修改循环以使用int 循环变量并在循环内计算i / 10.0。问题是你不能轻易预测在最后一次迭代中你会落在 10.0 的哪一边(在不完全是 0.1 的一百次加法之后)。从您编写循环的方式来看,您似乎不想要那个 9.99999999999999999998 值(舍入到 10.0 之后)。
【解决方案2】:
DecimalFormat dtime = new DecimalFormat("#.#"); 

for( double i = 0; i < 10 ; i+=0.1 ) 
{   
    String i2= Double.valueOf(dtime.format(i));
    rVoltsList.add( Double.toString( i2 ) );
}

【讨论】:

  • 如果使用这种方法,dtime 的声明应该移出循环。无需每次迭代都创建一个新的DecimalTime
猜你喜欢
  • 2020-10-16
  • 1970-01-01
  • 1970-01-01
  • 2015-01-26
  • 2011-12-27
  • 1970-01-01
  • 1970-01-01
  • 2012-03-04
  • 1970-01-01
相关资源
最近更新 更多