当传递一个从数字强制转换的整数时,如何从R的模数和上限/下限函数中获得一致的结果?

Dr.*_*run 1 floating-point r coercion

当我使用模运算符时,我注意到一些非常奇怪的浮点算术行为.如果我评估58 mod 2,我可以(并且应该)得到0.

> 58 %% 2
[1] 0
Run Code Online (Sandbox Code Playgroud)

这并不奇怪.但是如果"58"是某些浮点算术运算的结果呢?以下产生2的无意义结果.

> (0.58*100) %% 2
[1] 2
Run Code Online (Sandbox Code Playgroud)

我不确定为什么任何mod 2产生2都没关系,但我认为这可能是尝试修改非整数的结果.所以我试着强迫.

> as.integer(0.58*100) %% 2
[1] 1
Run Code Online (Sandbox Code Playgroud)

当我评估as.integer参数的上限时,这似乎是有意义的.

ceiling(as.integer(0.58*100))
[1] 57
Run Code Online (Sandbox Code Playgroud)

这没有任何意义,但更糟糕的是,它甚至不一致.

> ceiling(as.integer(0.58*100))
[1] 57
> ceiling(as.integer(0.57*100))
[1] 56
> ceiling(as.integer(0.56*100))
[1] 56
> ceiling(as.integer(0.55*100))
[1] 55
Run Code Online (Sandbox Code Playgroud)

最后,似乎序列生成的数字根据序列的长度表现不同!

> sapply(seq(from=0.55, to=0.58, by = 0.01), function(x) 
ceiling(as.integer(100*x)))
[1] 55 56 57 57
> sapply(seq(from=0.55, to=0.59, by = 0.01), function(x)                 
ceiling(as.integer(100*x)))
[1] 55 56 57 58 59
Run Code Online (Sandbox Code Playgroud)

有没有办法让我乘以两个数字,并将结果强制转换为一个整数,其上限等于我从as.integer得到的整数值?

Eri*_*hil 5

我不知道R,所以以下是基于浮点和软件的一般知识.

你说(0.58*100) %% 2生产2.它没有.它产生的值略低于2,但R的默认格式将其舍入以显示.首先,.58并不能完全代表R使用的浮动格式.假设它是IEEE-754基本的64位二进制浮点数,R转换为正确的舍入.然后0.58产生:

0.57999999999999996003197111349436454474925994873046875,
Run Code Online (Sandbox Code Playgroud)

0.58*100生产:

57.99999999999999289457264239899814128875732421875,
Run Code Online (Sandbox Code Playgroud)

(0.58*100) %% 2生产:

1.99999999999999289457264239899814128875732421875.
Run Code Online (Sandbox Code Playgroud)

当您使用浮点运算的残差运算时,您应该准备接受这样的结果.在算术模2中,1.99999999999999289457264239899814128875732421875非常接近0.如果它们不是为了您的目的而接近,那么残差和浮点运算可能不适合您的应用.

你说它没有意义ceiling(as.integer(0.58*100))产生57,但我们看到它的原因: 0.58*100是57.99999999999999289457264239899814128875732421875,所以将它截断为一个整数产生57.

接下来你要说这些不一致:

> ceiling(as.integer(0.58*100))
[1] 57
> ceiling(as.integer(0.57*100))
[1] 56
> ceiling(as.integer(0.56*100))
[1] 56
> ceiling(as.integer(0.55*100))
[1] 55
Run Code Online (Sandbox Code Playgroud)

这里一贯使用的规则是每个操作产生四舍五入到最接近的可表示值的精确数学结果.

从而:

0.58 ? 0.57999999999999996003197111349436454474925994873046875
0.58*100 ? 57.99999999999999289457264239899814128875732421875
0.57 ? 0.56999999999999995115018691649311222136020660400390625
0.57*100 ? 56.99999999999999289457264239899814128875732421875
0.56 ? 0.560000000000000053290705182007513940334320068359375
0.56*100 ? 56.00000000000000710542735760100185871124267578125
0.55 ? 0.5500000000000000444089209850062616169452667236328125
0.55*100 ? 55.00000000000000710542735760100185871124267578125
Run Code Online (Sandbox Code Playgroud)

关于这个:

> sapply(seq(from=0.55, to=0.58, by = 0.01), function(x) 
ceiling(as.integer(100*x)))
[1] 55 56 57 57
> sapply(seq(from=0.55, to=0.59, by = 0.01), function(x)                 
ceiling(as.integer(100*x)))
[1] 55 56 57 58 59
Run Code Online (Sandbox Code Playgroud)

我怀疑发生了什么是R不是迭代地计算循环索引(从.55开始并且每次都添加.01)但是使用某个公式独立地计算序列中每个元素的值.(这对于创建用于评估序列的可并行化算法是必要的.)处理此问题的常用方法是使用整数作为循环参数,然后根据需要缩放值,如下所示:

> sapply(seq(from=55, to=59, by=1), function(x)
ceiling(as.integer(100*(.01*x))))
Run Code Online (Sandbox Code Playgroud)

浮点运算近似于实数算术.当与连续函数一起使用时,轻微的算术误差会在结果中按比例(以某种方式)改变结果 - 输入或评估的变化会使结果沿连续函数移动.当与不连续函数一起使用时,轻微的算术错误可能会导致结果跨越不连续,从而导致跳跃.因此,对于算术模2,输入中从1.9999 ...到2的略微变化导致输出中从2变为0.如果要对不连续函数使用浮点运算,则应了解浮点运算及其行为.