我正在研究Java Puzzlers的第二个难题。
public class Change {
public static void main(String args[]) {
System.out.println(2.00 - 1.10);
}
}
Run Code Online (Sandbox Code Playgroud)
您会认为答案是0.9。但事实并非如此。如果您锻炼一下,您将获得0.8999999。给出的解决方案是
System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10")));
Run Code Online (Sandbox Code Playgroud)
现在它将打印0.9。我了解为什么打印0.89999。但是,当我好奇地调试BigDecimal类时,我发现在大多数地方都替换了许多常量值。我将在下面列出所有内容,并有兴趣了解其背后的原因。
BigDecimal.java行号394,
while (len > 10 && Character.digit(c, 10) == 0) {
offset++;
c = in[offset];
len--;
}
Run Code Online (Sandbox Code Playgroud)
此处为Character.digit(c,10)。
public static int digit(char ch, int radix) {
return digit((int)ch, radix);
}
Run Code Online (Sandbox Code Playgroud)
这里将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;
Run Code Online (Sandbox Code Playgroud)
Q2。如果深入研究代码,您将了解valBits是什么,而我无法理解为什么在某些地方使用了右移?
Q3。在这里您还可以看到使用了许多常数,例如63、52。为什么?
Q4。我可以理解,0x7ffL此处使用的十六进制将提高执行速度。同样,为什么在此处&使用带有十六进制常量的BitWise 运算符。
希望我的问题清楚。真诚的感谢您的耐心配合。
Q1:当然,基数是计算的基础。您正在使用以 10 为基数的数字;)
Q4:二进制中的 7ff:0111 1111 1111
如果您阅读了位移运算符的解释,Java“位移位”教程?你会看到 >> 63 丢弃了 63 个第一位并保留了最后一位。最后一位是符号位(对于有符号类型)。如果为 1,则该整数为负数,因此此处为 int 符号。
另外,您可以参考https://en.wikipedia.org/wiki/Floating_point了解浮点数的定义。52是为了区分指数和有效数。
Q4:当然,对于指数,您不想使用其中的“符号”位,因为它不是指数的一部分,因此掩码为 7ff。Bitwise & 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)
Run Code Online (Sandbox Code Playgroud)
但是: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)
Run Code Online (Sandbox Code Playgroud)
这就是 0x7ff 的用途。