请在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 —— 没有小数点后无限循环的数字序列是不可能的。
然而,我们在这里讨论的是字面语法。那么,为什么你要在数字中输入比需要的更多精度呢?如果你不想保持那个级别的精度,为什么还要输入呢?

或者你是说,通过查看字面量,根本无法知道它是否能放入双精度浮点数中吗?
通过查看字面量,可以知道它是否可以在不改变其精确值的情况下,非常合适地放入一个双精度浮点数中,或者不能。然而,这些值(用十进制表示)在包含的十进制位数上差异很大,从1位到我认为可能数百位。
出于好奇,您会提出什么规则来判断一个包含小数点的数字序列应该表示为双精度浮点数(double)还是BigDecimal呢?

鉴于IEEE 754双精度值和BigDecimal都有非常不同的关于算术行为的保证,例如,关于哪些算术结果是精确的,哪些不是,以及当结果不是精确的时它们是如何进行舍入的,如果必须显式地选择使用BigDecimal值,我觉得它似乎要更加可预测。

用另一种方式表达上一段的观点,就是评论一下你最初帖子中的一句话,你认为BigDecimal是相对于IEEE 754浮点数的一种“提升”。我认为这并不正确。它们只是不同。

例如,我非常确信您可以使用相同尺度的BigDecimal值进行许多加法运算和减法运算,并且结果总是保证是精确的。这不是double值的情况。
在写完这条消息后,我会真的尽力停止思考这件事。

这里有一条可能的规则可以想象,但我认为如果实施了它,其行为将会非常令人惊讶。

"如果非整数的十进制字面量可以精确地作为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,所以根据上述规则,这3个字面量应该是double,其余8个将被转换为BigDecimal。

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

我现在明白了。对于旁观者来说,以下这个链接帮助了我: 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的领域内,所以这种自动提升将会造成伤害。

感谢所有的细节。
...