请在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到可能几百年不等。
出于好奇,您会提出哪条规则来判断包含小数点的十进制数字序列应该表示为双精度浮点数还是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等从0.00到1.00的2位小数字面量,只有5个可以被精确表示为双精度浮点数:0.00、0.25、0.50、0.75和1.00。根据上面的规则,只有这5个字面量将是double类型,其余的所有都是BigDecimal。
我认为我对浮点数/double的理解可能过于狭隘。

现在我明白了。对于旁观者来说,这对我有帮助:[为什么0.1不存在于浮点数中](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。
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 and x <= b”。
by
是的,我太笨了。我总是把小数当作整数来处理,这根本就不合理。

我开始明白,没有简单的方法。无法仅仅在X位小数或X值之后提升为BigDecimal。你将需要一个如你所说的交错的转换,这将是奇怪且意外的。1.03是double还是bigdec?很难说。而且大多数时候,为了性能,你都想保持在double的领域内,所以这种自动提升将是伤害性的。

感谢所有这些详细的说明。
...