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

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

+1
语法和读取器

我发现这有点不一致,我可以键入

123423534634544234534634645342363462443649886756676645466767687

而它会自动升级到BigInt以匹配,无需我指定N后缀。

但是如果使用十进制

12.3423534634544234534634645342363462443649886756676645466767687

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

有什么原因吗?

1答案

+3

selected
 
最佳答案

我的猜测是,对于整数情况,值无法表示为64位或更小的整数大小是100%肯定的,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。

类似地,对于所有到1.00的0.00, 0.01, 0.02等两位小数的101个字面量,只有5个可以精确表示为double:0.00, 0.25, 0.50, 0.75和1.00。根据上述规则,只有这5个字面量是double类型,其余的都是BigDecimal。
我认为我对浮点/double的理解可能太局限了。

我现在明白了。对于旁观者来说,这对我有帮助:https://www.exploringbinary.com/why-0-point-1-does-not-exist-in-floating-point/

你所说的现在更合理。对于整数,你不能这样做。你不能简单地截断小数点后的X位数,因为在二进制中,一些可以适合的十进制数实际上并不适合。

因此,你不能直接说小数点后跟一个数字。因为0.1是可以被允许的,但在二进制中0.1在小数点后有无限位的数。

但是,也许我仍然有点困惑。我的想法是,如果我输入的十进制数在 Double/MIN_VALUE 和 DOUBLE/MAX_VALUE 范围内,它应该是一个双精度浮点数;如果不是,应该是一个 BigDecimal。这难道没有道理吗?所以 0.1 会读取为双精度浮点数,但 0.99999999999999999999 会读取为 BigDecimal。
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 位小数后提升到 BigDecimal,或者超过 X 的值。您需要按照您所说的交错进行,这会很奇怪并且不合预期,1.03 是会是双精度浮点数还是 BigDecimal?很难说。而且大多数时候,为了性能,您会希望停留在双精度浮点数的领域中,所以这种自动提升将是伤害性的。

感谢所有细节。
...