Я бы начал с удаления статических переменных из тела вашей функции. Они немного медленнее, так как должны проверять свое состояние (уже инициализировано или нет) при каждом вызове функции. Просто переместите их из области действия функции.
Почему вы используете такой короткий буфер? Вы уверены, что вам нужно записывать в файл каждый unsigned long long? Я бы предложил использовать что-то вроде unsigned char buffer[1024].
Тогда вам следует подумать, как избавиться от других операторов if.
Открытие файла, вероятно, будет намного медленнее, чем запись в него. В вашем дизайне вы минимизируете вызовы открытия файлов?
Ответ 4 · davka
если я правильно вас понял, вы хотите записать length младших битов длинного целого числа без знака, которое вы получаете. Вы можете сохранить цикл по входным битам, маскируя необходимые биты:
unsigned long long mask = (1ull << length) - 1; // creates a mask of 'length' 1's
BitBuffer = Data & mask;
в качестве примечания, я не понимаю, почему ваш тест и запись находятся внутри цикла в первой версии.
Ответ 5 · user9876
Прежде всего, вам нужно написать код так, чтобы он был понятен. Я не могу легко понять ни один из ваших фрагментов кода. Вот попытка переформатировать и реорганизовать первый, чтобы сделать его проще, и добавить некоторые комментарии:
/**
* @brief Write some bits to a file.
*
* The bits are written MSB-first to a temporary 64-bit integer, which is
* then written to the file in host byte-order.
*
* @param Data The data to write to the file. Only the least-significant
* Length bits are written. Of the bits that are written, the
* most significant bit is written first.
* @param Length The length of the data to write, in bits. Must be <= 64.
* @param OutFile The file to write to
*
* @note This function is not thread-safe
* @note This function stores some state in a static variable. You must
* ensure that the total data written is a multiple of 64 bits, or
* some data will be lost. You can only switch from one OutFile to
* another on a 64-bit boundry.
*/
void WriteBitsToFile(unsigned long long Data,
unsigned Length,
std::ofstream & OutFile)
{
static unsigned long long BitBuffer = 0;
static unsigned BitCounter = 0;
// Loop through input bits, one bit at a time
for (int i = (int)Length; i >= 0; --i)
{
// Get the input bit
unsigned long long NextBit = ((Data >> i) & 1);
// Add it to the temporary buffer
BitBuffer = ((BitBuffer << 1) | NextBit);
BitCounter++;
// If the temporary buffer is full, write it out
if (BitCounter == 64)
{
OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
BitCounter = 0;
}
}
}
Теперь, когда я понимаю, что вы пытаетесь сделать...
Ваша вторая версия выглядит намного лучше, потому что вы избегаете побитового цикла. Поскольку вы спрашиваете об оптимизации этого, я предполагаю, что у вас есть результаты профилирования, которые показывают, что это медленно? И я предполагаю, что вы пропускаете через это много данных?
Одной из возможных оптимизаций является запись в гораздо больший буфер (я бы предложил не менее 4 КБ). Это означает, что вам не нужно вызывать write() так часто. Вызов write() может быть относительно медленным.
Ответ 6 · AShelly
Вот один из способов сделать это с большим буфером. (на псевдо-C#)
const int wordSz= sizeof(unsigned long long)*8;
void WriteBitsToFile(unsigned long long Data, unsigned Length, std::ofstream & OutFile) {
static unsigned long long BitBuffer[BUFSZ+1] ={0};
static unsigned bitsSoFar = 0;
Data &= (1 << Length) - 1;
int index = bitsSoFar/wordSz;
int offset = bitsSoFar - (index*wordSz);
BitBuffer[index]|=Data<<offset;
int remainder = offset+length-wordSz;
if (remainder > 0)
{
index++;
BitBuffer[index]=Data>>(length-remainder);
}
bitsSoFar+=length;
if (bitsPacked > BUFSZ*wordSz)
{
OutFile.write((char*)BitBuffer, BUFSZ*sizeof(unsigned long long));
bitsSoFar-=BUFSZ*wordSz;
BitBuffer[0]=BitBuffer[BUFSZ];
}
}