【问题标题】:Using bit operations influences memory consumption? [closed]使用位操作会影响内存消耗吗? [关闭]
【发布时间】:2018-01-13 22:40:08
【问题描述】:

我正在做一个生物信息学的大学项目,遇到了一个非常奇怪的情况,我就是不明白。

为了优化计算生物序列中子序列哈希值的函数的 CPU 性能,我替换了以下内容:

hashValue += powf(4.0, k-i-1) * PHI_function((*seqence)[startIndex + i]);
//top of file has #include<cmath>

与:

hashValue +=  (0x1 << (2*(k-i-1))) * PHI_function((*seqence)[startIndex + i]);
//top of file does not have #include<cmath> since powf is not used

变量解释:

//k is the sub-sequence length
//i is a index going from 0 to k
//sequence -> pointer to bio-sequence string 
//hashValue is of type int
//
//PHI_function has the following signature: inline int HashTableCalculationMethod::PHI_function(char b)
// and only conatins: return (b & 0x6) >> 1; 
//which means
// if (b == 'A') {
//     return 0;
// } else if (b == 'C') {
//     return 1;
// } else if (b == 'G') {
//     return 2;
// } else if (b == 'T') {
//     return 3;
// }

这将程序时间性能提高了约 5 倍,但由于某种原因,内存消耗也从约 4GB 增加到了约 7.5GB(在我为该项目收到的样本上运行时)。

我确信这是由于 Git 版本跟踪而影响内存消耗的更改(我在修改前后都有提交)。

有人能解释一下这是如何影响程序内存消耗的吗?

项目位于link。提交改变性能的是 d39d055

提前谢谢你。

【问题讨论】:

  • 将两行代码放入带有断言的代码中,以检查它们总是给出相同的值。
  • 当你转换为 int 时,我想到解释内存差异的唯一一件事就是单精度浮点地板/截断。第一个版本实际上可能会丢失精度,导致错误地产生比预期结果更小的结果。
  • @TeamUpvote 你是对的,我通过 Richard Critten 建议的断言发现了这一点。但由于他的回答是在这样的评论中,我不知道如何接受它来结束问题
  • 您可以自己回答并接受它或接受 L. Serni 的。他似乎有一种预感,这与选角有关。如果您自己回答,可能会很方便地给出问题的详细答案以及您是如何解决的,以便其他人查看他们是否遇到类似情况。干杯!
  • 顺便说一句,对于未来的参考,请注意那些从浮点数转换为整数的问题。在这种情况下,四舍五入通常会给您想要的结果,例如:int int_val = static_cast&lt;int&gt;(flt_val + 0.5f); 这样,如果您喜欢15.9998f,它仍然会四舍五入为16。顺便说一句,你们喜欢战术角色扮演游戏吗?我也想对所有这些东西投赞成票,但我没有投赞成票!我稍后会投票!

标签: c++ performance memory-management


【解决方案1】:

我真的只能看到两个选项。

显然,您的代码仍然执行与以前相同的操作 - 无论您如何计算,4k-i-1 始终是相同的数字。或者是吗?新的计算产生一个整数,然后将它乘以 Phi。这是否可能导致 Phi 值被转换为整数以用于乘法目的? (似乎不太可能,但尝试将(1&lt;&lt;...) 转换为加倍以查看)。如果值的解释不同,那么这可能会影响哈希表中的冲突次数,从而影响内存。

上面的一个变体是(1 &lt;&lt; (2*(k-i-1))) 由于数据类型限制,powf() 的范围不同;您应该根据 k 检查可能的最大值。应该是k-i-1 始终为正数或零,并且始终低于 31(或者是 30?)或 63,具体取决于整数大小。

但是,您可以预先计算 powf。这为您提供了两全其美:快速计算和正确的结果。如果索引始终为正,则在初始化之前运行

// vector of doubles. All copacetic as long as
// maxValue... is correctly estimated. Otherwise,
// "hello, undefined behaviour".
for (x = 0; x <= maxValueForKMinusIMinusOne; x++) {
    powfTable[x] = powf(4.0, x);
}

并在内核计算中将powf(4.0, k - i - 1) 替换为powfTable[k-i-1]您可以通过任何有效域有限的函数调用来做到这一点。在这里,我猜你不能有超过,什么,七十个值?

如果不是这样,您可能在之前的提交中弄错了,在该提交中,最小化向量在调用之间是通用的。我无法遵循代码,但可能这会导致单个向量变得比它应该的更大 - 有点像反向 Jordan 表示?您不会在单元测试中注意到它,而这可能会让您相信更改没有改变 - 直到您在更大的集合上运行代码。

【讨论】:

  • 我尝试了以下演员: ((double)(0x1
  • 至于公共向量,我确保在调用之间调用 clear ,所以我认为这不是问题
  • @Richard Critten 建议我提出一个断言并确保两个版本始终产生相同的值。它们不会影响哈希桶冲突。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-05
  • 1970-01-01
  • 1970-01-01
  • 2010-09-06
  • 2013-02-22
相关资源
最近更新 更多