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

欢迎!请查阅关于页面以了解更多此功能的信息。

+1投票
语法和读取器

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

123423534634544234534634645342363462443649886756676645466767687

它将自动将其提升为BigInt来拟合,而不需要我指定N后缀。

但如果你使用十进制

12.3423534634544234534634645342363462443649886756676645466767687

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

这是为什么?

1 答案

+3投票
by
selected by
 
最佳答案

我的猜测是,对于整数情况,100%确定值无法表示为64位或更小的整数,Clojure只支持一种大整数类型作为默认类型。

对于你提到的非整数,那可能是一种精度过高的浮点数,或者精度过高的双精度浮点数,或者可能希望它是BigDecimal类型。我觉得编译器没有明确的方法来确定程序员究竟意图是什么。

请注意,当以十进制表示时,一些IEEE 754值的精确表示在十进制小数点后的位数要多得多,所以不能简单地通过计算小数点后的位数来区分它们。

-by
以下是一些关于最后一点的例子,注意到-40次方的2可以用一个有效位数和指数-40的IEEE 754算术表示。  以十进制精确写出来需要28个十进制位数,因为它等于(5^40) / (10^40),而5^40有28个十进制位数。

相反,十进制的0.1在二进制中需要一个永远重复的表示才能写成。  也就是说,它类似于尝试精确地以十进制写出1/3或1/7 -- 没有小数点后永远重复的十进制数是无法做到的。
-by
但在这里,我们谈论的是字面语法定义。  为什么要在数字中输入比所需的更多精度?  如果不需要那么高的精度,为什么要输入这些数字呢?

或者你是说,通过查看字面值无法知道它是否可以放入双精度值中吗?
-by
通过查看字面值可以知道它是否会完全保持其精确值不改变地放入一个双精度值中,或不会。  然而,这些值的集合,以十进制形式书写,包含相当多的十进制位数,从1到几百个位数不等。
-by
出于好奇,您会提出什么规则来判断一个包含小数点的十进制数字序列应该被表示为double还是BigDecimal呢?

由于IEEE 754双精度值和BigDecimal值在算术行为上的保障方式非常不同,例如在哪些算术结果的精度可以保证,哪些不能,以及当结果不精确时如何进行舍入,所以我认为如果必须显式选择使用BigDecimal值,那么这一点似乎更加可预测。

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

例如,我相当确信您可以在具有相同缩放的BigDecimal值上进行尽可能多的加法和减法操作,结果总是可以得到精确保证。对于double值,情况并非如此。
by
写完这条消息后,我真的会尽量停止思考这个问题。

这里有一个可以想象出的可能的规则,但我认为如果实现了这条规则,它的行为可能会很奇怪并且令人惊讶。

"如果非整数的十进制字面量可以精确地表示为double,就将其表示为double,否则将其表示为精确的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可以精确表示为double,因此根据上述规则,这三个将是double,其余的8个将变为BigDecimal。

同样,对于2位小数的101个字面量(从0.00到1.00),只有5个可以精确地表示为double:0.00, 0.25, 0.50, 0.75和1.00。根据上述规则,只有这5个字面量将是double类型,其余都将变为BigDecimal。
by
我认为我对float/double的理解可能过于狭隘。

我现在明白了。对于旁观者,以下内容有助于我:[链接](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范围内,它应该是一个双精度浮点数,如果不是,它应该是一个BigDec。这样的做法合理吗?所以0.1会被读取为double,但0.99999999999999999999会被读取为BigDec。
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”。
是的,我太笨了。我一直把小数当作整数来处理,这样做根本就不合理。

我开始明白,没有简单的方法。你不能只是将小数提升为BigDecimal后X位数字,或者超过X的值。你需要像我说的那样交错处理,这会很奇怪且不符合预期,1.03将是double还是bigdec?很难判断。而且,大多数情况下,为了性能,你想要保持在double的范围内,所以这种自动提升会有害。

感谢您提供的所有细节。
...