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

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

+1
语法和读取器

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

123423534634544234534634645342363462443649886756676645466767687

它将自动提升它为 BigInt 以适配,而无需我使用 N 后缀来指定。

但如果使用十进制

12.3423534634544234534634645342363462443649886756676645466767687

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

这是为什么?

1 答案

+3

最佳答案
 
最佳答案

我猜测对于整数情况,值绝对不能表示在64位或更小的整数大小,并且 Clojure 支持的唯一默认大整数类型。

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

请注意,当以十进制表示时,一些 IEEE 754 值的精确表示在十进制小数点后的数字位数比其他值要多得多,因此仅通过计算小数点后数字的位数是无法简单区分的。

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

相反,0.1的十进制表示要求以无限重复的形式在二进制中写出。 也就是说,它类似于试图以十进制形式准确写出1/3或1/7,因为这不可能不使用无限重复的十进制小数位数来完成。
但是,我们正在讨论的是字面量语法。那么,为什么还要在数字中输入比需要的更多精度呢?如果不需要那种精度的数值,为什么还要输入它们呢?

或者你是说,通过查看字面量无法知道它是否可以放于double中吗?
通过查看字面量,可以知道它是否会以完全不变的确切值放入double中,但这没有任何变化。 然而,这些值的集合,以十进制形式表示,包含的十进制数字位数差异很大,从1至上百位。
出于好奇,您会提出什么规则来确定一个包含小数点的十进制数字序列应该如何表示为双精度浮点数(double)或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个字面量类型为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并且x <= b”。
是的,我只是太笨了。我一直把小数当作整数对待,这根本说不通。

我开始意识到没有简单的办法。你不能在X位小数后或超过X的值后直接提升为BigDecimal类型。你需要像你所说的那样混合使用,这会非常奇怪和不一致。例如,1.03是会被当作double类型还是bigdec类型呢?很难说。而且,大多数情况下,为了性能,你都想保持在double的类型范围内,所以这种自动提升会有害。

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