大数的 BigDecimal 小数位

BigDecimal scale for large numbers

我试图了解 BigDecimal 的小数位数,但它的行为很奇怪,我不明白为什么。这里有几个例子:

Double d = new Double(1000000d);
int scale = new BigDecimal(d.toString()).scale();

本例中的比例为 1,这对我来说是正确的。 d.toString() 的结果是“1000000.0”。

Double d = new Double(10000000d);
int scale = new BigDecimal(d.toString)).scale();

本例中的比例将为 -6。谁能解释为什么? d.toString() 的结果是“1.0E7”。

我认为是位数导致的,但如果我去:

Double d = new Double(11111111d);
int scale = new BigDecimal(d.toString()).scale();

预计比例为 -8,但突然变成了 0。 d.toString() 的结果是“1.1111111E7”。

在阅读了 scale() 的 Javadoc 后,这些不同的比例对我来说毫无意义:

Returns the scale of this BigDecimal. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. For example, a scale of -3 means the unscaled value is multiplied by 1000.

我非常感谢解释 BigDecimal 在数字很大时的行为方式。

提前致谢!

您看到您的报告的行为是因为您在提供的小数上调用 toString(),在您的某些示例中,它以指数表示法表示,然后由 BigDecimal 保留选择比例。

如果您将双精度数直接提供给 BigDecimal 构造函数,您始终会得到 0。

new Double(1000000d).toString() //1.0E7

Double d = new Double(1000000d);
int scale = new BigDecimal(d).scale(); //0

Double d = new Double(10000000d);
int scale = new BigDecimal(d).scale(); //0

Double d = new Double(11111111d);
int scale = new BigDecimal(d).scale(); //0

更新:

scale 本身并不是一个有用的属性。必须结合unscaledValue来考虑。表示的数字是 unscaledValue × 10 ^ -scale.

BigDecimal d = new BigDecimal(1000000d)
BigDecimal e = d.setScale(2)

int dScale = d.scale() //0
int dUnscaled = d.unscaledValue() //1000000

int eScale = e.scale() //2
int eUnscaled = e.unscaledValue() //100000000

de都是1000000的表示。但是,e 保留了 2 个尾随零(小数点后的零)。

d.toString() //1000000
e.toString() //1000000.00

你得到的刻度是小数位数有一定意义:

  • 1000000d -> 1000000.0 -> 0:点右边的数字没有意义,结果为0;
  • 10000000d -> 1.0E7 -> -6:点右边的数字很重要,就好像你将幂非规范化 10 得到 6 个零;
  • 11111111d -> 1.1111111E7 -> 0:点右边的所有数字都有意义,将幂非规范化 10 可以获得更多信息,因此如果你想 "can't" 规范化数字保留此信息。这样(数字非规范化),你在点右边有 0 个数字。

编辑

如评论,第一行错了,一定是1000000d -> 1000000.0 -> 1。原因是具有指数的数字与格式化数字具有不同的行为(在获取比例时)。

1的值是由于BigDecimal计算点右边的数(本例为1,单个0),减去要删除的数字(在本例中有一个,单个 0)并添加数学精度(默认情况下为一)-> 结果 = 1.