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

欢迎!有关如何使用此功能的更多信息,请参阅关于页面。

+1
语法和读取器

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

123423534634544234534634645342363462443649886756676645466767687

并且它会自动提升它为BigInt以适应,无需我使用N后缀进行指定。

但如果是使用十进制

12.3423534634544234534634645342363462443649886756676645466767687

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

有什么原因吗?

1 回答

+3

已被选中
 
最佳答案

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

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

请注意,以十进制形式写出的某些IEEE 754值的精确表示在小数点后的数字比其他数字多得多,因此您不能仅通过计算小数点后的数字数量来区分这一点。

以下是一些支持上述观点的例子,请记住,2的-40次幂可以用IEEE 754算术中使用1位有效数字和指数-40来表示。  用十进制精确地写出它需要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值进行大量的加法和减法,而且结果总是保证是精确的。这并不适用于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。
我认为我对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范围内,它应该是一个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值。您需要像您说的那样错位,这会很奇怪,也很意外。1.03是double还是bigdec?很难说。而且,通常出于性能考虑,您还想留在大double领域,所以这种自动提升会很痛苦。

感谢提供所有这些详细信息。
...