如何将此范围编码C ++代码段转换为高性能的Haskell?

时间:2013-06-20 11:24:40

标签: performance haskell

我知道Haskell可以翻译下面的代码,但我对它的表现不太了解不了多少:

typedef unsigned long precision;
typedef unsigned char uc;

const int kSpaceForByte = sizeof(precision) * 8 - 8;
const int kHalfPrec = sizeof(precision) * 8 / 2;

const precision kTop = ((precision)1) << kSpaceForByte;
const precision kBot = ((precision)1) << kHalfPrec;


//This must be called before encoding starts
void RangeCoder::StartEncode(){
  _low = 0;
  _range = (precision) -1;
}

/*
  RangeCoder does not concern itself with models of the data.
  To encode each symbol, you pass the parameters *cumFreq*, which gives
  the cumulative frequency of the possible symbols ordered before this symbol,
  *freq*, which gives the frequency of this symbol. And *totFreq*, which gives
  the total frequency of all symbols.
  This means that you can have different frequency distributions / models for
  each encoded symbol, as long as you can restore the same distribution at
  this point, when restoring.
*/
void RangeCoder::Encode(precision cumFreq, precision freq, precision totFreq){
  assert(cumFreq + freq <= totFreq && freq && totFreq <= kBot);
  _low += cumFreq * (_range /= totFreq);
  _range *= freq;
  while ((_low ^ _low + _range) < kTop or
         _range < kBot and ((_range= -_low & kBot - 1), 1)){
    //the "a or b and (r=..,1)" idiom is a way to assign r only if a is false.
    OutByte(_low >> kSpaceForByte); //output one byte.
    _range <<= sizeof(uc) * 8;
    _low <<= sizeof(uc) * 8;
  }
}

我知道,我知道“编写几个版本并使用标准来查看哪些有用”。我不知道我的选择是什么,或者避免愚蠢的错误。

到目前为止,这是我的想法。一种方法是使用State monad和/或镜头。另一种方法是将循环和状态转换为显式递归。我在某处读过显式递归往往在ghc上表现不佳。我认为使用ByteString Builder是输出每个字节的好方法。假设我在64位平台上运行,我应该使用未装箱的Word64参数吗?如果我将精度降低到32位,压缩质量不会显着降低。 GHC会更好地优化吗?

由于这不是1-1映射,因此使用StateP的管道将导致非常简洁的代码,其中我将一次请求一个参数,然后让while循环响应字节的字节。不幸的是,当我对它进行基准测试时,似乎管道开销(不出所料)非常大。由于每个符号都可以导致许多字节输出,因此感觉有点像带状态的concatMap。也许这将是惯用的解决方案?但是,连接字节列表对我来说听起来不是很快。 ByteString有一个concatMap。也许这是正确的方法?编辑:不,不是。它需要一个ByteString作为输入。

当我完成时,我打算在Hackage上发布包,所以你可以提供的任何建议(或实际代码!)将使社区受益:)。我计划将此压缩用作编写内存效率非常高的压缩映射的基础。

1 个答案:

答案 0 :(得分:1)

  

我在某处读过显式递归往往在ghc上表现不佳。

没有。 GHC产生慢速的递归机器代码,这种代码无法减少(或GHC&#34;不想要&#34;减少)。如果可以展开递归(我不会在你的代码片段中看到它的任何基本问题),它将转换为与C或C ++中的while循环几乎相同的机器代码。

  

假设我在64位平台上运行,我应该使用未装箱的Word64参数吗?如果我将精度降低到32位,压缩质量不会显着降低。 GHC会更好地优化吗?

你的意思是Word#吗?让GHC处理它,使用盒装类型。我从未遇到过只能通过使用未装箱的类型获得一些利润的情况。使用32位类型对64位平台没有帮助。

优化GHC性能的一个一般规则是尽可能避免数据结构。如果您可以通过函数参数或闭包传递数据,请使用该机会。