Кодирование чисел Variant Си ? Вывод в бинарные файлы
Пытаюсь сделать задание 1 вот отсюда, алгоритм кодирования, декодирования и генерации взят оттуда же. Не могу понять как работает encode_variant. Почему он возращает size_t ? Ну пробовал потыкать на вход даю число 122 допустим, возвращается 1, даю 222, возвращается 2. Как то не очень оно похоже на закодированное число. И следующий вопрос как из этого закодированного числа с помощью decode получить исходное. Не понимаю в каком виде нужно передать число 2, допустим, чтобы его назад декодировать в 222. Задание состоит в генерации двух файлов с 100000000 случайными числами, в одном должны быть числа без кодирования в другом с ним и нужно сравнить размеры файлов, получаю файлы одинакового размера 3907 КБ, по логике вещей после кодирования эти числа должны занимать меньший объем. Вот код
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#define ERROR_FILE_OPEN -3
size_t encode_varint(uint32_t value, uint8_t* buf)
{
assert(buf != NULL);
uint8_t* cur = buf;
while (value >= 0x80) {
const uint8_t byte = (value & 0x7f) | 0x80;
*cur = byte;
value >>= 7;
++cur;
}
*cur = value;
++cur;
return cur - buf;
}
uint32_t decode_varint(const uint8_t** bufp)
{
const uint8_t* cur = *bufp;
uint8_t byte = *cur++;
uint32_t value = byte & 0x7f;
size_t shift = 7;
while (byte >= 0x80) {
byte = *cur++;
value += (byte & 0x7f) << shift;
shift += 7;
}
*bufp = cur;
return value;
}
/*
* Диапазон Вероятность
* -------------------- -----------
* [0; 128) 90%
* [128; 16384) 5%
* [16384; 2097152) 4%
* [2097152; 268435455) 1%
*/
uint32_t generate_number()
{
const int r = rand();
const int p = r % 100;
if (p < 90) {
return r % 128;
}
if (p < 95) {
return r % 16384;
}
if (p < 99) {
return r % 2097152;
}
return r % 268435455;
}
int main(void){
uint8_t* mybuffer;
mybuffer = malloc(sizeof(uint8_t));
FILE *output1 = NULL;
FILE *output2 = NULL;
output1 = fopen("C:/Users/forjo/Documents/C Prog/Programms/bitwise/compressed.dat","wb");
if (output1 == NULL) {
printf("Error opening file");
getch();
exit(ERROR_FILE_OPEN);
}
output2 = fopen("C:/Users/forjo/Documents/C Prog/Programms/bitwise/uncompressed.dat","wb");
if (output1 == NULL) {
printf("Error opening file");
getch();
exit(ERROR_FILE_OPEN);
}
size_t count = 1;
for (int i=0; i<1000000; i++){
uint32_t random = generate_number();
uint32_t compress = encode_varint(random,mybuffer);
fwrite(&compress, sizeof(compress), count, output1);
fwrite(&random, sizeof(random), count, output2);
}
return 0;
}
Ответы (1 шт):
Ну как бы алгоритм простой. Числа типа uint32_t занимают в памяти 4 байта (32 бита). А реальные числа можно представить в памяти меньшим количеством байт. Например, в общем случае uint числа от 0 до 255 - хватит одного байта для записи. Конкретно в этом алгоритме используется только 7 бит, а 8 бит - служебный. Поэтому 1 байта хватит для записи чисел от 0 до 127.
Вот этот алгоритм в файл output2 записывает каждый раз по 4 байта, а в файл output1 - то количество байт, которого достаточно для отображения числа.
Но у Вас много ошибок:
int main(void)
{
// uint8_t* mybuffer;
// mybuffer = malloc(sizeof(uint8_t)); // неправильно - буфер должен быть не меньше 4 байт
uint8_t mybuffer[5];
size_t count = 1;
for (int i=0; i<1000000; i++)
{
uint32_t random = generate_number();
size_t compress = encode_varint( random, mybuffer); // compress - количество байт
// fwrite(&compress, sizeof(compress), count, output1); // неправильно! нужно записывать буфер.
fwrite(mybuffer, 1, compress, output1); // записывается compress значений по 1 байту
fwrite(&random, sizeof(random), 1, output2); // записывается 1 значение размером sizeof(uint32_t) байт
}
return 0;
}