Number 或 BigInteger 和 BigDecimal 中的错误(或者在这些的 API 文档中)?

发布于 2024-10-02 17:51:08 字数 1302 浏览 2 评论 0 原文

根据 Number.longValue() 的规范,该方法应该...

以长整型形式返回指定数字的值。这可能涉及舍入或截断。

但是,BigInteger(和 BigDecimal)会重写此方法并返回其整数部分的 64 个低位。代表。例如,来自 BigInteger 的文档:

[...]如果此 BigInteger 太大而无法放入 long 中,则仅返回低位 64 位。[...]

我声称“这可能涉及舍入或截断。”没有说明该方法实际应该返回什么,或者实现或文档中存在错误。

你同意吗,还是我的推理有错误?


示例代码:

import java.math.BigInteger;
import static java.math.BigInteger.*;

public class Main {
    public static void main(String[] args) {

        BigInteger i = valueOf(Long.MAX_VALUE);

        // Result: Long.MAX_VALUE, just as expected.
        Number n1 = i;
        System.out.println(n1 + " -> " + n1.longValue());

        // I expect to get the "rounded" value Long.MAX_VALUE
        Number n2 = i.add(ONE);
        System.out.println(n2 + " -> " + n2.longValue());

        // I expect to get the "rounded" value Long.MAX_VALUE
        Number n3 = i.multiply(TEN);
        System.out.println(n3 + " -> " + n3.longValue());
    }
}

输出:

9223372036854775807 -> 9223372036854775807
9223372036854775808 -> -9223372036854775808
92233720368547758070 -> -10

According to the specification of Number.longValue() the method should...

Returns the value of the specified number as a long. This may involve rounding or truncation.

However, the BigInteger (and BigDecimal) overrides this method and returns the 64 low bits of the integer part of the number it represents. From the docs of BigInteger for example:

[...]if this BigInteger is too big to fit in a long, only the low-order 64 bits are returned.[...]

I claim that either "This may involve rounding or truncation." doesn't say anything about what the method actually should return, or, there is a bug in implementation or documentation.

Would you agree, or do I have a mistake in my reasoning?


Example code:

import java.math.BigInteger;
import static java.math.BigInteger.*;

public class Main {
    public static void main(String[] args) {

        BigInteger i = valueOf(Long.MAX_VALUE);

        // Result: Long.MAX_VALUE, just as expected.
        Number n1 = i;
        System.out.println(n1 + " -> " + n1.longValue());

        // I expect to get the "rounded" value Long.MAX_VALUE
        Number n2 = i.add(ONE);
        System.out.println(n2 + " -> " + n2.longValue());

        // I expect to get the "rounded" value Long.MAX_VALUE
        Number n3 = i.multiply(TEN);
        System.out.println(n3 + " -> " + n3.longValue());
    }
}

Output:

9223372036854775807 -> 9223372036854775807
9223372036854775808 -> -9223372036854775808
92233720368547758070 -> -10

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

美胚控场 2024-10-09 17:51:08

BigInteger.longValue() 的文档继续如下:

请注意,此转换可能会丢失有关 BigInteger 值的总体大小的信息,并且返回具有相反符号的结果

这重新定义(或澄清)了 Number.longValue() 定义的行为。这很好,尽管有时会产生误导。例如,java.util.Set 重新定义了 add 方法的行为(通过限制重复项)。如果您传递一个Collection,您可能期望它保存任何值,但具体实现已经重新定义了此行为。

更新:我检查了 Long.valueOf(Long.MAX_VALUE).intValue() 的行为方式。它打印-1。所以我认为对于浮点数来说,“舍入或截断”只是一种可能性。否则,Number 类将转换方式完全留给实现者。所以是的 - 它没有透露任何信息。我不会说这有那么糟糕,但它肯定具有误导性。

The documentation of BigInteger.longValue() continues with:

Note that this conversion can lose information about the overall magnitude of the BigInteger value as well as return a result with the opposite sign.

This redefines (or clarifies) the behaviour defined by Number.longValue(). This is fine, although it is sometimes misleading. For example java.util.Set redefines the behaviour of the add method (by constraining duplicates). If you pass a Collection you may expect it to hold any values, but the concrete implementation has redefined this behaviour.

Update: I checked how does Long.valueOf(Long.MAX_VALUE).intValue() behaves. And it prints -1. So I'd assume that by "round or truncate" is just a possibility, regarding floating point numbers. Otherwise the Number class leaves the way of conversion entirely to implementors. So yes - it does not tell anything about it. I wouldn't say it is that bad, but it is certainly misleading.

臻嫒无言 2024-10-09 17:51:08

我没有看到你的问题,这与你尝试表示特定数字类型范围之外的数字时得到的垃圾有什么不同?

final Number n = Long.MAX_VALUE;
System.out.println(n + " -> " + n.intValue());

prints

9223372036854775807 -> -1

您是否希望 API 告诉您,如果您传递无效输入,您将获得无效输出?

I don't see your question, how is this any different from the garbage you get whenever you try and represent a number outside the bounds of a particular numeric type?

final Number n = Long.MAX_VALUE;
System.out.println(n + " -> " + n.intValue());

prints

9223372036854775807 -> -1

Do you want the API to tell you that you'll get invalid output if you pass invalid input?

漫漫岁月 2024-10-09 17:51:08

“这可能涉及舍入或截断”这一措辞出现在 longValue()shortValue()charValue( )byteValue() “nofollow noreferrer">Number,因此很明显,“截断”旨在包括丢失重要的高阶位在某些情况下。

问题实际上在于术语“截断”通常意味着低阶位的丢失。 (这就是我在 30 年前的数值分析课程中所记得的。维基百科也同意。 )

相比之下,JLS 5.1.3< /a> 描述了相同的过程(当缩小整型原始类型时),如下所示:

有符号整数到整型 T 的窄化转换会简单地丢弃除 n 个最低位之外的所有位,其中 n 是用于表示类型 T 的位数。

所以,是的,我同意 javadoc 是不正确的。提交错误报告。

注意

我最初删除了这个,因为我认为我提交错误报告的建议可能是徒劳的(基于我过去处理文档错误报告的经验)。但是@aioobe已经提交了一份错误报告...(错误ID:7000825)

The wording "This may involve rounding or truncation" appears in the javadocs for the longValue(), shortValue(), charValue() and byteValue() of Number, so it is clear that "truncation" is intended to include loss of significant high order bits in some cases.

The problem really is that the term "truncation" conventionally means loss of lower order bits. (That's how I remember it from my numerical analysis course, 30 years ago. And Wikipedia agrees.)

By contrast, the JLS 5.1.3 describes the same process (when narrowing integral primitive types) as follows:

A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T.

So yes, I agree that the javadoc is incorrect. Submit a bug report.

NOTE

I had originally deleted this because I thought my suggestion to submit a bug report was probably futile (based on my past experience with documentation bug reports). But @aioobe has submitted a bug report ... (Bug ID: 7000825)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文