Java中的BigDecimal类 - 常量值背后的原因

5

我正在解第二个Java Puzzlers谜题。

public class Change {
  public static void main(String args[]) {
    System.out.println(2.00 - 1.10);
  }
}

你可能认为答案是0.9。但实际上并不是。如果你计算一下,结果是0.8999999。解决方案如下:

System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10")));

现在它将打印0.9。我理解为什么它打印0.89999。然而,在我好奇地调试BigDecimal类时,我发现有许多常数值被替换在大多数地方。我将列出所有这些并且希望了解背后的原因。 BigDecimal.java第394行。
               while (len > 10 && Character.digit(c, 10) == 0) {
                    offset++;
                    c = in[offset];
                    len--;
                }

Here Character.digit(c,10).

public static int digit(char ch, int radix) {
        return digit((int)ch, radix);
    }

这里将10作为基数传递。
Q1. 为什么要传递10?

BigDecimal.java第732行。

int sign = ((valBits >> 63)==0 ? 1 : -1);
        int exponent = (int) ((valBits >> 52) & 0x7ffL);
        long significand = (exponent==0 ? (valBits & ((1L<<52) - 1)) << 1
                            : (valBits & ((1L<<52) - 1)) | (1L<<52));
        exponent -= 1075;

问题2:如果您深入研究代码,您就可以理解valBits是什么,但我无法理解为什么在某些地方使用了右移运算符?

问题3:在这里,您还可以看到像63、52之类的许多常数被使用。 为什么呢?

问题4:我可以理解在这里使用十六进制0x7ffL将增加执行速度。 再次问一下,为什么要与十六进制常量使用按位 & 运算符。

希望我的问题很清楚。真诚感谢您的耐心。


1
Q1:假设这段代码来自BigDecimal的构造函数,那么这段代码正在解码值的char[]表示。因此,使用了基数10。 - Arnaud Denoyelle
1
Q3:valBits 是一个 long 类型,因此它用 64 位表示。所以 valBits >> 63 给出了第 64 位,也就是符号位。 - Arnaud Denoyelle
1
Q1 因为它是一个十进制数。 Q2-4 因为它正在解码一个 double - user207421
1个回答

3

Q1:当然,基数是计算的基础。您正在使用十进制数字 ;)

Q4:7ff的二进制表示为:0111 1111 1111

如果您阅读位移运算符的解释,请参考Java“位移”教程?,您将看到 >> 63舍弃前63个位并保留最后一位。最后一位是符号位(对于有符号类型)。如果它是1,则整数为负数,因此有int sign。

另外,您可以参考https://en.wikipedia.org/wiki/Floating_point了解浮点数的定义。52是用来区分指数和有效数字的。

Q4: 当然,对于指数,您不想在其中使用'sign'位,因为它不是指数的一部分,因此需要使用7ff进行掩码。按位与0x7ff就可以做到这一点;它只会在第一位上放置0,并将其他位保留在相同状态(请参见'AND'运算符的真值表https://en.wikipedia.org/wiki/Truth_table

编辑:

Q4补充说明:如果指数为12,则第一位将是类似于:

0000 0000 1100 ... (positive value) (ex: 1x10^12)
1000 0000 1100 ... (negative value) (ex: -1x10^12)

但是:1000 0000 1100 是2060十进制。

如果您应用“掩码”:

  1000 0000 1100 & 0111 1111 1111 -> 0000 0000 1100 (12 decimal)
  AND
  0000 0000 1100 & 0111 1111 1111 -> 0000 0000 1100 (12 decimal)

这就是0x7ff的作用。

请问您能否进一步解释一下第四个问题的答案?比如,为什么使用那个特定的十六进制数? - Vignesh Gopalakrishnan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接