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

欢迎!请参阅关于页面以了解有关如何操作的一些更多信息。

+1
语法和读取器

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

123423534634544234534634645342363462443649886756676645466767687

它会自动转换为BigInt以适配,无需我指定N后缀。

但是如果使用十进制

12.3423534634544234534634645342363462443649886756676645466767687

不会自动转换为BigDecimal,除非显式添加M后缀。相反,会截断到双精度。

有什么原因吗?

1 个答案

+3

选定
 
最佳答案

我的猜测是在整数情况下,100%确定该值不能表示为64位或更小的整数大小,Clojure只支持一个作为默认的大整数类型。

对于您提到的非整数数,这可能是具有太多精度位数的浮点数,或双精度数,或者可能需要BigDecimal类型。我想不出编译器可以明确确定程序员意图的方法。

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

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

相反,十进制形式的0.1需要重复表示才能用二进制表示。  也就是说,这类似于试图在十进制中精确地表示1/3或1/7——没有在小数点后使用无穷重复的数字系列是不可能的。
但在这个情况下,我们在谈论字面语法。那么,您为什么会将比所需的精度更多的精度输入到数字中呢?为什么要输入那些并不需要那种精度级别的值呢?

或者,您是说,通过查看字面量,无法知道它是否适合一个双精度浮点数?
通过查看字面量,您可以在没有任何改变其精确值的情况下知道它是否适合双精度浮点数。  然而,这些值的集合,以十进制形式书写,它们的十进制数字数量差异很大,从1到我认为的上百。
出于好奇,您会提出什么规则来决定一个包含小数点的十进制数字序列应该表示为双精度浮点数或BigDecimal?

鉴于IEEE 754双精度值和BigDecimal值在算术行为上有非常不同的保证(例如,在哪个算术结果是精确的,哪个不是精确的,以及当结果不是精确的时它们如何进行四舍五入),在我看来,如果必须显式选择使用BigDecimal值,那么这将是更加可预测的。

另一种表达上一段内容的方法是评论你在原始帖子中提到的一点,就是你认为BigDecimal是对IEEE 754浮点数的一种“提升”。我不这么认为。它们只是不同。

例如,我非常确定你可以在具有相同缩放比例的BigDecimal值上执行尽可能多的加法和减法运算,并且结果总是保证是精确的。这不是双精度值的情况。
by
我真的会尽力在写下这则信息后不再去想这件事。

这里可能有了一条可以想象出的规则,但我想如果将其实现,其行为会让你感到非常奇怪。

"如果非整数值的小数字面量可以被精确地表示为双精度浮点数,则将其表示为双精度浮点数;否则,将其作为一个精确的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可以被精确地表示为双精度浮点数,所以根据上面提到的规则,这三个将是双精度浮点数,其余的将会转换为BigDecimal。

类似地,对于从0.00,0.01,0.02等一直到1.00的两位小数的101个字面量,其中只有5个可以精确表示为双精度浮点数:0.00,0.25,0.50,0.75和1.00。根据上面提到的规则,只有这5个字面量将会是类型double,其余都将转换为BigDecimal。
by
我认为我对浮点数的理解可能过于狭隘。

现在我明白了。对于旁观者,以下链接对我有帮助:https://www.exploringbinary.com/why-0-point-1-does-not-exist-in-floating-point/

你现在的说法有道理。在整数上你不能这么做。你不能简单地截断小数点后的X位数字,因为在二进制中,一些本应适应的十进制小数不能适应。

所以你不能只写0.10。因为0.1是允许的,但是0.1在二进制中有无限多个小数点后的位。

但是,也许我仍然有些困惑。我的想法是如果我输入的十进制数在Double/MIN_VALUE和DOUBLE/MAX_VALUE范围内,那么它应该是一个双精度浮点数;如果不是,则应该是一个BigDecimal。这听起来还是靠谱的吗?所以0.1将会被读取为双精度浮点数,而0.99999999999999999999将会被读取为BigDecimal。
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”。
是的,我在犯傻。我一直把小数当作整数处理,但这根本说不通。

我开始明白没有简单的解决办法。你不可能在 X 位小数或 X 值之后简单地提升为 BigDecimal,你必须像您所说的那样交错处理,这将很奇怪,预料之外。1.03 会是 double 还是 bigdec?很难确定。而且,大多数时候,为了性能,你都想保持在 double 的领域,所以这个自动提升会是一个损害。

感谢所有这些细节。
...