Excel如何正确评估事实(170)/事实(169)?

Excel如何正确评估事实(170)/事实(169)?,excel,floating-point,floating-point-precision,Excel,Floating Point,Floating Point Precision,170!接近浮点双精度的极限:171!将溢出 然而170!长度超过300位 因此,这是不可能的!可以用浮点精确表示 但是Excel返回170的正确答案!/169!. 为什么会这样?我希望会出现一些错误,但它会返回一个整数值。Excel是否知道如何优化此计算?如果您找到最接近170的倍数!和169!,是的 double oneseventy = 5818033100654137.0 * 256; double onesixtynine = 8761273375102700.0; 乘以二的相同幂。

170!接近浮点双精度的极限:171!将溢出

然而170!长度超过300位

因此,这是不可能的!可以用浮点精确表示

但是Excel返回170的正确答案!/169!.

为什么会这样?我希望会出现一些错误,但它会返回一个整数值。Excel是否知道如何优化此计算?

如果您找到最接近170的倍数!和169!,是的

double oneseventy = 5818033100654137.0 * 256;
double onesixtynine = 8761273375102700.0;
乘以二的相同幂。最接近这些商的倍数正好是170.0

而且,Excel可以计算170!乘以169!到170

William Kahan有一篇论文叫做,他在那里讨论了Excel中的一些疯狂行为。可能Excel并没有精确计算170,而是对您隐藏了一个真实的ulp。

如果您找到最接近170的倍数!和169!,是的

double oneseventy = 5818033100654137.0 * 256;
double onesixtynine = 8761273375102700.0;
乘以二的相同幂。最接近这些商的倍数正好是170.0

而且,Excel可以计算170!乘以169!到170


William Kahan有一篇论文叫做,他在那里讨论了Excel中的一些疯狂行为。也许Excel并没有精确地计算170,而是对你隐藏了一个真实的ulp。

tmyklebu的答案已经很完美了。但我想知道更多。 如果实现n!是一件微不足道的事情,比如返回双n*n-1

下面是一个Smalltalk片段,但您可以用许多其他语言进行翻译,这不是重点:

(2 to: 170) count: [:n | 
    | num den |
    den := (2 to: n - 1) inject: 1.0 into: [:p :e | p*e].
    num := n*den.
    num / den ~= n].
答案是12

所以你们并不是特别幸运,因为舍入到最接近的偶数舍入模式的良好特性,在这169个数字中,只有12个不符合预期。 哪一个?通过选择替换计数,您将得到: 244759618196101104114122146

如果我手头有Excel,我会要求评估146/145!.

奇怪的是,一个不那么天真的解决方案,用大整数算法计算出精确的阶乘,然后转换成最近的浮点,效果并不好

(2 to: 170) reject: [:n | 
    n factorial asFloat / (n-1) factorial asFloat = n]
导致:


tmyklebu的答案已经很完美了。但我想知道更多。 如果实现n!是一件微不足道的事情,比如返回双n*n-1

下面是一个Smalltalk片段,但您可以用许多其他语言进行翻译,这不是重点:

(2 to: 170) count: [:n | 
    | num den |
    den := (2 to: n - 1) inject: 1.0 into: [:p :e | p*e].
    num := n*den.
    num / den ~= n].
答案是12

所以你们并不是特别幸运,因为舍入到最接近的偶数舍入模式的良好特性,在这169个数字中,只有12个不符合预期。 哪一个?通过选择替换计数,您将得到: 244759618196101104114122146

如果我手头有Excel,我会要求评估146/145!.

奇怪的是,一个不那么天真的解决方案,用大整数算法计算出精确的阶乘,然后转换成最近的浮点,效果并不好

(2 to: 170) reject: [:n | 
    n factorial asFloat / (n-1) factorial asFloat = n]
导致:


有关Excel不符合其实现的IEEE 754规范的情况,请参阅。尽管结论是正确的,但您问题中的“因此”是可疑的。10^22的长度为23位,因此根据同样的推理,它不可能用binary64精确表示,但它可以。170! 两者都有很多数字,不能用二进制64精确表示。@PascalCuoq Yep,170!要求有效位为170阶乘高位-170阶乘低位+1->854位。有趣的是,您的10^22示例是双精度中最后一个可表示的十次方,因为22!也是最后一个可表示的阶乘2到:170 detect:[:n | n factorial asFloat~=n factorial]->23I非常希望FACTx/FACTy在Excel不符合其实现的IEEE 754规范的情况下针对ySee进行优化。尽管结论是正确的,但您问题中的“因此”是可疑的。10^22的长度为23位,因此根据同样的推理,它不可能用binary64精确表示,但它可以。170! 两者都有很多数字,不能用二进制64精确表示。@PascalCuoq Yep,170!要求有效位为170阶乘高位-170阶乘低位+1->854位。有趣的是,您的10^22示例是双精度中最后一个可表示的十次方,因为22!也是最后一个可表示的阶乘2到:170 detect:[:n | n阶乘asFloat~=n阶乘]->23I非常希望FACTx/FACTy针对y@YogiBear:枫树给我169!/2^1012 * 2^53 ~= 8761273375102700.341917118244573688. “我很确定这是对的。”帕斯卡罗克:不管什么原因,我只听到人们叫他比尔·卡恩。不管他的名字写在哪里,他似乎都叫威廉·卡汉。我听说人们叫他“威廉”或“维尔维尔”,但“比尔”对我来说是个新名字。让人们把威廉的名字英语化是没有意义的,因为这个名字看起来根本不像威廉
“Velvel”,然后将笔名改为“Bill”。我非常喜欢拼写英语化的讽刺。@YogiBear:Maple给了我169!/2^1012 * 2^53 ~= 8761273375102700.341917118244573688. “我很确定这是对的。”帕斯卡罗克:不管什么原因,我只听到人们叫他比尔·卡恩。不管他的名字写在哪里,他似乎都叫威廉·卡汉。我听说人们叫他“威廉”或“维尔维尔”,但“比尔”对我来说是个新名字。让人们把威廉的名字英语化是没有意义的,这个名字甚至看起来都不像“Velvel”,然后把笔名改为“Bill”。我很喜欢拼写英语英语化的讽刺意味。我并不奇怪正确四舍五入的阶乘表现得更糟。正如tmyklebu提到的,使用naive方法,假设乘法从小到大依次进行!170的计算方法是将170与用于计算的相同计算结果相乘!169问题类似于d1*d2/d2在浮点运算中是否为d1,d1为双精度`且d2为双精度,有效位中设置了少量数字,这在某些情况下会有所帮助。对于正确舍入的阶乘,取而代之的是d1=舍入到doubler1,d2=舍入到doubler2,r2/r1=170。对于正确舍入的阶乘表现更差,我并不感到惊讶。正如tmyklebu提到的,使用naive方法,假设乘法从小到大依次进行!170的计算方法是将170与用于计算的相同计算结果相乘!169问题类似于d1*d2/d2在浮点运算中是否为d1,d1为双精度`且d2为双精度,有效位中设置了少量数字,这在某些情况下会有所帮助。使用正确的四舍五入阶乘,取而代之的是d1=四舍五入到二倍,d2=四舍五入到二倍,r2/r1=170。