【问题标题】:R-language: Efficient code to do set operations with bigz-class values?R 语言:使用 bigz 类值进行集合操作的高效代码?
【发布时间】:2022-06-12 04:47:35
【问题描述】:

gmp的当前版本不支持设置操作,如intersectsetdiff等。我正在做一些数字序列的工作(参见OEIS的例子)并且需要处理大整数的大集合。我目前坚持使用各种循环来生成所需的差异或交叉点;虽然我可能会生成已编译的(Rccp 等)代码,但我希望在现有的 R 函数和包中找到一种方法。

【问题讨论】:

  • 您能否添加有关您正在使用的对象的更多详细信息?例如,集合有多长,数字有多大? gmp 甚至没有一个好的 sort() 功能,所以我认为这会很棘手。
  • Rmpfr这样的管道 -> sets -> github EnriquePH/OEIS.R?
  • @user2554330 问题是 bigz - 类对象(以及 bigq )没有可用于设置操作功能的方法。所以我不能做,例如 intersect 即使在 as.bigz(1:4)as.bigz(3:6) 上。数字序列通常会超过 max(int),所以我必须使用扩展数学。
  • 这是“任意准确..”小插图中的“阶乘”示例,暗示“对整数感到满意”。我向您学习的 LMGTFY 并没有让我们失望。
  • @Waldi 我确实使用了这种方法,它确实可以正常工作。缺点是速度非常慢。如果我做一个 while 或 for- 循环来逐一比较集合中的元素,它比转换成和转换出字符要快。

标签: r set gmp set-intersection


【解决方案1】:

我可能弄错了,但是使用 mprf 对象可以访问基础 R intersectunionsetdiff,而 sort(... 需要包裹在 mprf(sort(...), 'bits') 中:

library(Rmprf)

f3 <- mpfr(5:9, 53)
f4 <- mpfr(8:12, 53)

intersect(f3,f4)
2 'mpfr' numbers of precision  53   bits 
[1] 8 9

setdiff(f3,f4)
3 'mpfr' numbers of precision  53   bits 
[1] 5 6 7

f3 %in% f4
[1] FALSE FALSE FALSE  TRUE  TRUE

# large integers from vignette
ns <- mpfr(1:24, 120)
fact_ns <- factorial(ns)
fact_ns[20:24]
5 'mpfr' numbers of precision  120   bits 
[1]      2432902008176640000     51090942171709440000   1124000727777607680000
[4]  25852016738884976640000 620448401733239439360000

pasc80 <- chooseMpfr.all(n = 80, 77)[40:49]
pasc80
10 'mpfr' numbers of precision  77   bits 
 [1] 107507208733336176461620 104885081691059684352800  97393290141698278327600
 [4]  86068488962431036661600  72375774809317008101800  57900619847453606481440
 [7]  44054819449149483192400  31869443856831541032800  21910242651571684460050
[10]  14308729894903957198400

mpfr(sort(union(fact_ns[20:24], pasc80)), 77)
15 'mpfr' numbers of precision  77   bits 
 [1]      2432902008176640000     51090942171709440000   1124000727777607680000
 [4]  14308729894903957198400  21910242651571684460050  25852016738884976640000
 [7]  31869443856831541032800  44054819449149483192400  57900619847453606481440
[10]  72375774809317008101800  86068488962431036661600  97393290141698278327600
[13] 104885081691059684352800 107507208733336176461620 6204484017332394393600

所以对于这些操作sets 是不必要的,并且假设您的工作流程适合基于Rmprf 的对象。

由于问题是在“精确度”的上下文中提出的,因此人们可能不希望将集合提升或降级为最高/最低“prec”的功能,而是有意参与决策(尽管,诚然,我找了一个)。

在这里,将下面的 f3 和 f4 重命名为 f7 和 f8:

getPrec(f7)[1]
[1] 10
getPrec(f8)[1]
[1] 20
intersect(roundMpfr(f7, 20), f8)
2 'mpfr' numbers of precision  20   bits 
[1] 9 6
intersect(f7, roundMpfr(f8, 10))
2 'mpfr' numbers of precision  10   bits 
[1] 9 6

因此,设置操作似乎需要“精度处理”,但如果在创建 mpfr 时,默认值将使输入呈现相同的精度是合理的,则可以避免这种额外的循环。使用 OEIS 作为输入:

library(OEIS.R) # git clone of EnriquePH/OEIS.R --no-build-vignettes
A011784 <- OEIS_bfile('A011784')
max(nchar(A011784$data$A011784))
[1] 221
max(nchar(A078140$data$A078140))
[1] 228

# so we see precision handling here, perhaps
A011784_228 <- mpfr(A011784$data$A011784, 228)
A078140_228 <- mpfr(A078140$data$A078140, 228)

intersect(A011784_228,A078140_228)
2 'mpfr' numbers of precision  228   bits 
[1] 1 3

啊,这么少的共同点。而且可能不是您的序列在 OEIS 中,而是检查与您的“来自野外”的序列的相似性,这并不能反映您的工作流程。

还有一些相关的,从最近的新闻中轻松阅读primitive sets

【讨论】:

  • 不幸的是,你被误导了,就像我一样。尝试f3 &lt;- mpfr(c(3,5,9,6,4),10 )f4 &lt;- mpfr(c(6,7,8,10,9),20)intersect 的结果会因为精度不同而为空。因此,如果在每次设置操作之前我要将两个对象的“Precbits”重置为相同的值,它可能会正常工作,但这会导致大量的处理开销。
【解决方案2】:

bigz 存储在list 而不是vector

library(gmp)

intersect(as.bigz(1:4), as.bigz(3:6))
#Big Integer ('bigz') object of length 2:
#[1] 1 2

intersect(as.list(as.bigz(1:4)), as.list(as.bigz(3:6)))
#[[1]]
#Big Integer ('bigz') :
#[1] 3
#
#[[2]]
#Big Integer ('bigz') :
#[1] 4

setdiff(as.list(as.bigz(1:4)), as.list(as.bigz(3:6)))
#[[1]]
#Big Integer ('bigz') :
#[1] 1
#
#[[2]]
#Big Integer ('bigz') :
#[1] 2

【讨论】: