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

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

+1投票
语法和读取器

我觉得这有点不一致,我可以输入

123423534634544234534634645342363462443649886756676645466767687

它将自动提升到BigInt以适应,而不需要我通过N后缀来指定。

但是使用十进制

12.3423534634544234534634645342363462443649886756676645466767687

不会自动提升到BigDecimal,除非显式添加M后缀。否则它会被截断为双精度。

这是为什么?

1 个答案

+3投票

选择
 
最佳答案

我的猜测是,对于整数情况,值绝对不能在64位或更小的整数大小中表示,而Clojure只支持一种大整数类型作为默认类型。

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

请注意,在十进制表示法中,IEEE 754值的精确表示有些数字在小数点后的位数比其他数字要多得多,因此不能仅仅通过计数小数点后的数字数量来区分这一点。

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

反过来,十进制中的0.1需要无穷循环的表示才能用二进制表示。也就是说,这与试图用十进制精确写出1/3或1/7类似——不可能实现,除非在小数点后有无限循环的数字序列。
by
但是,我们这里在讨论字面量语法。那么,为什么要在数字中键入不需要的更多精度呢?为什么在不想要这种精度水平的情况下还要键入这些数字呢?

或者你是在说,从字面量中无法看出它是否可以适合双精度浮点数(double)吗?
by
通过查看字面量可以知道,它是否会无任何值的变化而准确无误地放入双精度浮点数(double),或者不行。然而,这些值的一组,用十进制写,在包含多少位十进制数字方面差异很大,从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。

类似地,对于有两位小数、从0.00, 0.01, 0.02等,到1.00的101个字面量,其中只有5个可以精确表示为双精度浮点数:0.00, 0.25, 0.50, 0.75, 和1.00。根据上述规则,只有这5个字面量将是double类型,其余都是BigDecimal。
头像
我认为我对浮点数/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的范围内,它应该是一个double,如果不是,则应该是一个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 and x <= b”。
我是真的笨。我一直把小数当作整数对待,这根本说不通。

我开始明白没有简单的方法。你不能只在X位十进制或者超过X值后提升为BigDecimal。你就像是按照你说的那样交织在一起,这会很奇怪,也很出人意料,1.03是double还是bigdec?很难区分。而且大多数时候,为了性能,你想要留在double的领域内,所以这种自动提升会很不利。

感谢所有的细节。
...