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

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

+1
语法和读取器

我发现这有点不一致,因为我可以编写

123423534634544234534634645342363462443649886756676645466767687

并且它会自动将其提升为 BigInt 以适应,而我不需要使用 N 后缀来指定。

但是使用十进制时

12.3423534634544234534634645342363462443649886756676645466767687

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

有什么原因吗?

1 答案

+3

被选中
 
最佳答案

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

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

请注意,以十进制编写时,IEEE 754 值的精确表示在十进制点后有更多数字,所以您不能仅通过计数十进制点后的数字数量来区分这一点。

以下是一些关于最后一点的例子,请注意,2的-40次幂可以使用一个有效位和一个指数为-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到1.00),只有5个可以被精确地表示为双精度浮点数:0.00、0.25、0.50、0.75和1.00。根据上述规则,仅这5个字面值将是双精度浮点数类型,其余都将转换为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 范围内,它应该是一个双精度浮点数,如果不是,则应该是 BigDecimal。这样做是否仍然合理?因此,0.1 应该被读取为双精度浮点数,而 0.99999999999999999999 则应被读取为 BigDecimal。
by
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”。
by
是的,我只是太傻了。我一直把小数当整数处理,这根本说不通。

我开始意识到,没有简单的方法。你不能只是将小数提升到 BigDecimal,或者超过 X 的值。你需要像你说的那样交叉组合,这会很奇怪和不寻常,1.03 是双精度浮点数还是 BigDecimal?很难说。而且大多数时候,为了性能,你都想停留在双精度浮点数的领域,所以这种自动提升会是有害的。

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