对于逻辑值向量,当一个位向量每个条目消耗1位时,为什么R会分配4个字节?(有关示例,请参阅此问题.)
现在,我意识到R还有助于存储NA值,但是不能用额外的位向量来完成吗?换句话说,为什么仅仅使用廉价的两位数据结构就不够了?
对于它的价值,Matlab使用1个字节作为逻辑,但它不利于NA值.我不确定为什么MathWorks不满足于一位功能,更不用说两位数据结构了,但是他们有花哨的裤子营销人员...... [我会在这个问题上为所有它值得"两点"加牛奶.;-)]
更新1.我认为所提供的架构原因是有道理的,但这感觉有点事后.我没有检查32位或16位R来查看它们的逻辑有多大 - 这可以为这个想法提供一些支持.从R Internals手册中可以看出,逻辑向量(LGLSXP)和整数(INTSXP)在每个平台上都是32位.我可以理解整数的通用大小,与字大小无关.类似地,逻辑的存储似乎也与字大小无关.但它太大了.:)
另外,如果字大小参数如此强大,看到Matlab(我认为它是一个32位的Matlab)只消耗1个字节似乎很奇怪 - 我想知道MathWorks是否选择通过权衡编程复杂性来提高内存效率以及查找子词对象的一些其他开销.
此外,肯定还有其他选择:正如Brian Diggs所说,该bit软件包有助于位向量,这对上述问题中的问题非常有用(通过从4字节logical值转换为任务获得8X-10X的加速速度位向量).虽然访问存储器的速度很重要,但从信息理论的角度来看,移动30-31个额外的无信息位是浪费的.例如,可以使用类似于此处描述的整数的内存技巧- 获取一堆额外的内存(V单元),然后在位级处理事物(a la bit()).为什么不这样做并NA为长向量保存30位(值为1,为1 )?
如果我的RAM和计算速度受到布尔值的影响,我打算转而使用bit,但这是因为在某些情况下节省97%的空间很重要.:)
我认为这个问题的答案将来自对R的设计或内部有更深入理解的人.最好的例子是Matlab对其逻辑使用不同的大小,在这种情况下,内存字大小不是答案.Python可能与R类似,因为它的价值.
短语的一个相关方法可能是:为什么LGLSXP在所有平台上都会有4个字节?(CHARSXP通常是较小的,也不会那么有用吗?为什么不进行更小的,只是过度分配?)(更新使用的想法CHARSXP可能是假的,因为操作CHARSXP不像整数那样有用如sum,利用相同的数据结构作为字符可能节省空间,但将限制其现有的方法可能在其上进行操作.更合适的考虑因素是使用较小的整数,如下面讨论的).
更新2已经有慕名相对于一个怎样一些很好的和启发性的答案,应该执行布尔速度和编程效率的目标的检索和处理.我认为Tommy的答案特别合理,因为它在R中出现的原因似乎来自于两个前提:
为了支持对逻辑向量的添加(注意"逻辑"由编程语言/环境定义,并且与布尔值不同),最好通过重用代码来添加整数来实现.在R的情况下,整数消耗4个字节.在Matlab的情况下,最小的整数是1个字节(即int8).这可以解释为什么不同的东西会为逻辑写作带来麻烦.[给那些不熟悉R,它支持上逻辑值的很多数值的操作,例如sum(myVector),mean(myVector)等]
遗留支持使得除了R和S-Plus已经做了很长时间以外的其他事情变得非常困难.而且,我怀疑在S,S-Plus和R的早期,如果有人做了很多布尔操作,他们在C中做了它们,而不是试图用R中的逻辑做这么多工作.
对于如何实现更好的布尔处理的目的,其他答案是很棒的 - 不要天真地假设一个人可以得到任何单个位:加载一个字最有效,然后屏蔽不感兴趣的位,如德瓦尔描述过.如果为R的布尔操作编写专门的代码(例如我在交叉表中的问题),这是非常非常有用的建议:不要迭代位,而是在单词级别工作.
感谢所有人提供了一套非常全面的答案和见解.
我从Matlab那里得到了一个条件调试标志:dbstop if infnan 这里描述.如果设置,此条件将在遇到Inf或NaN遇到时停止代码执行(IIRC,Matlab没有NA).
如何在R中以比在每次赋值操作后测试所有对象更有效的方式实现此目的?
目前,我认为这样做的唯一方法是通过以下方式进行黑客攻击:
is.finite(),在这个问答描述,每一个元件上.body()修改代码来调用一个单独的功能,每一个操作或者可能只是每个任务,测试所有对象(也可能在所有环境中的所有对象)之后.tracemem标识已更改的变量,并仅检查这些变量是否为错误值.第一个选项是我目前正在做的事情.这很乏味,因为我无法保证我已经检查过所有内容.第二个选项将测试所有内容,即使对象尚未更新.这是浪费大量时间.第3个选项将涉及修改NA,NaN和无限值(+/- Inf)的赋值,以便产生错误.这似乎最好留给R Core.第四个选项就像第二个选项 - 我需要调用一个单独的函数列出所有内存位置,只需要识别那些已更改的ID,然后检查值; 我甚至不确定它是否适用于所有对象,因为程序可能会进行就地修改,这似乎不会调用该duplicate函数.
我错过了更好的方法吗?也许Mark Bravington,Luke Tierney的一些聪明的工具,或者相对基本的东西 - options()在编译R时类似于参数或标志?
示例代码下面是一些非常简单的示例代码,可以使用addTaskCallbackJosh O'Brien提出的函数进行测试.代码不会中断,但在第一种情况下确实会发生错误,而在第二种情况下不会发生错误(即badDiv(0,0,FALSE)不会中止).我还在调查回调,因为这看起来很有希望.
badDiv <- function(x, y, flag){
z = x / y
if(flag == TRUE){
return(z)
} else {
return(FALSE)
}
}
addTaskCallback(stopOnNaNs)
badDiv(0, 0, TRUE)
addTaskCallback(stopOnNaNs)
badDiv(0, 0, FALSE)
Run Code Online (Sandbox Code Playgroud)
注意1.我对标准R操作的解决方案感到满意,尽管我的很多计算涉及通过data.table或使用的对象bigmemory …