在非常小的值上使用R中的圆函数返回零

时间:2014-05-21 12:58:30

标签: r floating-point rounding floor

我有时必须处理非常低的p值并以表格格式呈现它们。 R返回的值可以具有长有效数字(即小数点后的数字)。 现在因为p值总是如此之低,我倾向于在将它们写入.xls或.tsv文件之前将它们缩短。(只是为了使表看起来很漂亮!!)

我正在使用R version 3.0.0 (2013-04-03)

一些背景和示例:

R中的

9.881313e-208将在我的表格中9.88e-208

我可以使用R中的round函数来执行此操作。

round(9.881313e-208, 210)
[1] 9.88e-208

然而,e的功效值在每种情况下都会有所不同,因为有很多这样的情况,我使用以下公式: -

x = 9.881313e-208
round(x,abs(floor(log10(x)-2)))   ## I came to this following trial and error
[1] 9.88e-208

我已经根据经验测试了这个公式,它适用于不同的情况,如: -

a <- c(1.345678e-150,8.543678e-250,5.555555e-303, 0.01123, 4.523456e-290)
round(a,abs(floor(log10(a)-2)))
[1] 1.35e-150 8.54e-250 5.56e-303  1.12e-02 4.52e-290

现在问题开始时e的力量超过数字306(即使307很好,但在308之后开始变得奇怪)

## Example 1:
b <- c(1.345678e-306,1.345678e-307,1.345678e-308, 1.345678e-309, 1.345678e-310)
round(b,abs(floor(log10(b)-2)))
[1] 1.35e-306 1.30e-307 1.00e-308  0.00e+00  0.00e+00

## Example 2:
b <- c(3.345678e-306,3.345678e-307,3.345678e-308, 3.345678e-309, 3.345678e-310)
round(b,abs(floor(log10(b)-2)))

[1] 3.35e-306 3.30e-307 3.00e-308  0.00e+00  0.00e+00

## Example 3:
b <- c(7.345678e-306,7.345678e-307,7.345678e-308, 7.345678e-309, 7.345678e-310)
round(b,abs(floor(log10(b)-2)))

[1] 7.35e-306 7.30e-307 7.00e-308 1.00e-308  0.00e+00

另外,我直接检查了这些:

round(7.356789e-306,308)
[1] 7.36e-306

round(7.356789e-307,309)
[1] 7.4e-307

round(7.356789e-308,310)
[1] 7e-308

round(7.356789e-309,311)
[1] 1e-308

round(7.356789e-310,312)
[1] 0

round(7.356789e-311,313)
[1] 0

我在这里遗漏了一些微不足道的事情,或round函数是否超出e-308的分辨率限制。我知道这些值非常低,几乎等于零,但我仍然希望有确切的值。我在使用Python看到了这个问题的一些答案,(参见How right way to round a very small negative number?)但是我有什么建议可以在R中克服这个问题吗?

非常感谢

干杯

阿斯温

2 个答案:

答案 0 :(得分:4)

这个答案是基于R&#39的浮点数由IEEE 754 64位二进制数表示的假设。这与报告的结果一致,并且本身很可能。

对绝对幅度低于约2e-308的数字进行大量算术是非常有问题的。低于该点,精度会随着幅度下降。最小的可表示数字,约4.9E-324,其表示中有一个重要位。它的一对相邻数字是0和大约1.0E-323。 任何舍入错误都会将其减少为零或加倍。它不会遇到仅影响其十进制表示中的低有效位数的细微舍入误差。同样,round也无法轻微改变。它可以保持不变,加倍,返回0,或者做出更大的改变。

有关正在发生的事情的更多说明,请参阅Denormal number

解决方案是,如果可能的话,避免对这么小的数字进行算术运算。正如评论中已经指出的那样,一种好的方法是使用对数。如果你需要处理非常大和非常小的数字,这是唯一的方法。

如果这是不可能的,并且您的数字都很小,请考虑使用2的中等大小进行缩放。范围内两个的幂是完全可表示的,并且乘以它们仅改变指数,没有舍入误差。在舍入之前,您可以通过常量缩放要存储在文本文件中的所有数字。

答案 1 :(得分:0)

要解决此问题,您可以使用Rmpfr库。

示例:

library(Rmpfr)
x <- mpfr(7.356789e-311, 80)
round(x, 313)
1 'mpfr' number of precision  1040   bits 
[1]7.36000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008e-311
相关问题