2024 Clojure状态调查中分享你的想法!

欢迎!请参阅关于页面了解更多关于如何工作的信息。

+1
语法和读取器

我发现这有点不一致,我可以输入

123423534634544234534634645342363462443649886756676645466767687

它将自动提升为BigInt以适应,无需我指定N后缀。

但使用十进制

12.3423534634544234534634645342363462443649886756676645466767687

不会自动提升到BigDecimal,除非明确添加M后缀。相反,它将截断为双精度。

为什么会有这样的区别呢?

1 回答

+3

被选中
 
最佳答案

我认为对于整数字面量,100%确定其值不能在64位或更小的整数大小中表示,Clojure只支持一种大整数类型作为默认类型。

对于你提到的非整数字面量,这可能是浮点数有太多的精度位,或者双精度浮点数有太多的精度位,或者可能会希望它是BigDecimal类型。我觉得编译器无法明确判断程序员意图的类型。

请注意,当以十进制形式书写时,IEEE 754值的精确表示有些在十分位之后有更多的数字,所以你不能只通过计算十分位之后的数字数量来区分这一点。

以下是对最后一点的几个例子,请注意,2 的 -40 次幂可以在 IEEE 754 运算中使用一个有效位和指数 -40 来表示。用十进制定义它需要 28 位十进制数字,因为它是 (5^40) / (10^40),而 5^40 有 28 位十进制数字。

相反,十进制中的 0.1 需要无限循环表示来在二进制中写出来。换句话说,尝试在十进制中确切地写 1/3 或 1/7 本书输出 ähnlich -- 没有无限循环的数字系列就无法完成。
然而,我们在谈论字面量语法。那么,你为什么要对你不需要那么高精度的数字输入更多的精度?如果你不想达到那么高的精度,为什么要打成那样呢?

或者你是在说,通过查看字面量,无法知道它会否适合双精度或不会?
通过查看字面量可以知道,它是否会无变化地、没有任何改变地安装在双精度内,但这组值在十进制中包含的十进制数字数量相当广泛,从 1 到几百不等。
出于好奇心,您会提出什么规则来确定一个包含小数点的十进制数序列应该以双精度浮点数还是BigDecimal表示呢?

鉴于IEEE 754双精度值和BigDecimal值在算术行为方面非常不同,例如,在哪些算术结果是精确的以及哪些不是,以及当结果不精确时的舍入方式,我感到如果必须明确选择使用BigDecimal值时,它似乎更有可预测性。

另一种表达前一段话观点的方式是评论您在原始帖子中的一句话,即您认为BigDecimal是IEEE 754浮点数的一种“提升”。我不这么认为。它们只是不同的。

例如,我非常确信您可以在具有相同精度的BigDecimal值上执行尽可能多的加法和减法操作,而且结果总是保证是精确的。对于双精度值并非如此。
在写完这条消息后,我会尽量不再去想这个点了 :-)

这里有一个可以想象出的规则,但如果实现了,我认为其行为会很奇怪。

"如果非整数的十进制字面量可以精确地表示为一个双精度浮点数,则将其作为双精度浮点数,否则将其作为精确的BigDecimal(对于任何有限的十进制数序列都是可能的)。"

考虑所有这些字面量:0.0、0.1、0.2、0.3、0.4、0.5、0.6、0.7、0.8、0.9、1.0。在这11个字面量中,只有0.0、0.5和1.0可以精确地表示为双精度浮点数,因此根据上述规则,这3个将标记为双精度浮点数,其余的8个将标记为BigDecimal。

类似地,对于有两位小数点的101个字面量,从0.00、0.01、0.02等,到1.00,其中只有5个可以精确表示为双精度浮点数:0.00、0.25、0.50、0.75和1.00。根据上述规则,只有这些5个字面量将标记为双精度浮点数,其余的都将标记为BigDecimal。
我认为我之前对浮点数/double的理解可能太有限了。

现在我明白了。对于旁听者,这个链接对我有帮助:[https://www.exploringbinary.com/why-0-point-1-does-not-exist-in-floating-point/](https://www.exploringbinary.com/why-0-point-1-does-not-exist-in-floating-point/)

您现在说的是很有道理。您不能对整数做这样的事情。您不能在浮点数后简单截断X位数字,因为在二进制中,有些可以匹配的十进制数字实际上不匹配。

因此,您不能简单地说10位小数。因为0.1会被允许,而在二进制中,0.1在小于十分之一的位置处有无限多的位数。

但是,也许我仍然有些困惑。我的想法更倾向于,如果我输入的小数在 Double/MIN_VALUE 和 Double/MAX_VALUE 范围内,它应该是 double 类型,否则应该是 BigDecimal。这样不就合理了吗?所以 0.1 应该被解析为 double,而 0.99999999999999999999 应该被解析为 BigDecimal。
by
Double/MIN_VALUE 约为 4.9E-324,而 Double/MAX_VALUE 约为 1.7976931348623157E308,所以你的示例值 0.99999999999999999999 确实在 Double/MIN_VALUE 和 Double/MAX_VALUE 之间。
我这里假设,可能不正确,即“x 在 a 和 b 之间”是指“a <= x 和 x <= b”。
by
是的,我只是有点傻。我一直像整数一样处理这些小数,这根本没有意义。

我开始意识到,没有简单的办法。你不能只是在小数点后有 X 位数字后提升到 BigDecimal,或者超过 X 个值。你需要像你说的那样交错进行,这将很奇怪,令人意外。1.03 是 double 还是 bigdec?很难说。而且,大多数情况下,为了性能,你想要留在 double 的领域,所以这种自动提升将会很糟糕。

感谢所有详细的解释。
...