Android - 避免字符串中的指数转换为双倍转换

时间:2013-11-14 05:44:13

标签: android string double type-conversion

我试图从edittext获取值并存储为字符串。然后它转换为double。虽然转换最多7个字符正常运行,但如果我尝试添加超过7个结果是1.23456789E8。这是我的代码

String value = txtData.txtSearch.getText().toString();
// value = "987654321.45"

double amount1 = Double.parseDouble(value);
// amount1 = 9.8765432145E8

double amount2 = 0.05;

double result = (amount1 * amount2) / 100;
// result = 4.3827160725E14

计算后得到4.3827160725E14这是不正确的正确答案是493827.16

如何在不丢失精度的情况下获得正确的值?

4 个答案:

答案 0 :(得分:3)

我解决了。我现在使用BigDecimal而不是double,我的代码是

String value = txtData.txtSearch.getText().toString();
// value = "987654321.45"

BigDecimal amount1 = new BigDecimal(value);
// amount1 = "987654321.45"

BigDecimal amount2 = new BigDecimal(0.05);

BigDecimal result = (amount1.multiply(amount2)).divide(new BigDecimal(100));
result = result.setScale(2, RoundingMode.FLOOR);
// result = 493827.16

答案 1 :(得分:0)

以下代码给出了您的预期结果:

public class DoubleTest {
 public static void main(String[] args) {
      double amount1 = Double.parseDouble("987654321.45");
      double amount2 = 0.05;
      double result = (amount1 * amount2) / 100;
      System.out.println(result);
 }
}

那么,你确定你从txtData.txtSearch.getText().toString();获得了你认为的价值吗?

顺便说一句,如果你真的对任意精度感兴趣(例如在处理金钱时),请使用BigDecimal。

答案 2 :(得分:0)

试试这个:

double result = (amount1 * amount2) / 100.0;
string resultInMyFormat =  new DecimalFormat("#.#").format(result);

答案 3 :(得分:0)

  

如何避免将字符串以指数形式转换为双精度?

我想我们都错了。

这是您的示例:

// value = "987654321.45"

double amount1 = Double.parseDouble(value);
// amount1 = 9.8765432145E8

大概是评论中的内容被打印了;例如使用调试器或调用println

那你为什么看到指数/科学记号?

好吧,这不是由于字符串解析为double的方式所致。实际上,将double转换成字符串以进行打印时,$ cat Test.java import java.text.DecimalFormat; public class Test { public static void main(String[] args) { String value = "987654321.45"; double amount = Double.parseDouble(value); System.out.println(amount); DecimalFormat format = new DecimalFormat("0.########"); System.out.println(format.format(amount)); } } $ java Test 9.8765432145E8 987654321.45 就发生了。示例:

double

看到了吗?我从“ 987654321.45”开始,将其转换为double。然后以两种不同的方式打印它。并为相同的println(double)值得到了两个不同的字符串表示形式


那为什么System.out这样打印数字?

好吧...

  1. PrintStreamprintln(double)
  2. print(double)等效于println(),后跟print(double)
  3. double使用StringString.valueOf(double)转换为valueOf(double)
  4. Double.toString(double)返回与toString(double)相同的表示形式
  5. 如果数字的幅值小于10 -3 或大于或等于10 7,则指定
  6. toString(double)以使用科学计数法。

这是在各自的javadocs中指定的 all 。最突出的是Double.doubleToRawLongBits(double)的{​​{3}}。


如果您不相信我,可以查看Java语言规范和IEE 754标准中的浮点表示形式。参见javadoc

如果需要,甚至可以使用double来检查4.3827160725E14值的位表示形式。


最后

  

计算后,我得到493827.16,这是不正确的,正确答案是493827.1607250001

当我重复该计算时,使用System.out.println(double)得到答案BigDecimal...。 (请注意,没有科学计数法,因为该数字小于10 7 。)

计算的确切答案(1987654321.45 * 0.05)/ 100 493827.160725。确切答案与Java给我们的答案之间的差异是由计算机浮点数舍入误差引起的。之所以会发生这种情况,是因为IEE 754表示形式实际上是具有二进制尾数和二进制指数的二进制表示形式,并且因为该尾数具有固定数量的精度二进制数字。

此舍入误差是使用IEE 754表示进行计算所固有的。如果要减轻它的影响,可以使用BigDecimal来代表您的数字。但是您应该意识到,即使BigDecimal也不是精确的:

  • 您无法使用BigDecimal精确表示Pi或任何其他非理性数字。

  • 许多有理数没有精确表示为BigDecimal;例如1.0 / 3.0的值。

因此,从理论上讲,您仍然需要关注0.sqltable | 1.df的舍入错误。