-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathvbencoder.py
More file actions
149 lines (113 loc) · 3.75 KB
/
vbencoder.py
File metadata and controls
149 lines (113 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
- Nombre: vbencoder.py
- Descripción: permite encode/decode de enteros a/desde Variable Byte.
- Autor: Agustín González
- Modificado: 18/04/18
'''
import time
import math
def compute_encoded_size(numbers):
'''Calcula el tamaño de codificación final de la lista dada.
Args:
numbers (int list): números a codificar.
Returns:
size (int): tamaño de codificación final en bits.
'''
size = 0
for number in numbers:
# Bits requeridos para representar el número.
required_bits = math.floor(math.log(number, 2))+1
# Agregación de bits de overhead (1 por cada byte).
required_bits += math.ceil(required_bits/8)
# Utilización de bytes 'completos'.
number_size = math.ceil(required_bits/8) << 3 # *8 = << 3
size += number_size
return size
def encode(number):
'''Codifica un número a Variable Byte.
Args:
number (int): número a codificar.
Returns:
encoded (byte list): número codificado como array de bytes.
'''
encoded = []
while True:
# Add de byte al principio de la lista.
encoded = [number & 127] + encoded # n & 127 = n % 128
if number < 128:
break
else:
number = number >> 7 # n >> 7 = int(n / 128)
# Add de 128 para activar el bit 8 del último byte (indica terminador).
encoded[-1] += 128
return encoded
def decode_number(encoded, offset=0):
'''Decodifica un número codificado en Variable Byte desde el offset de la
secuencia de bytes dada.
Args:
encoded (byte list): número/s codificado/s.
offset (int): nro. de bit de inicio de lectura.
Returns:
number (int): número decodificado.
offset (int): nuevo offset.
'''
number = 0
byte_index = offset >> 3 # n >> 3 = int(n / 8)
for i in range(byte_index, len(encoded)):
byte = encoded[i]
# number = 128 * number + byte
number = (number << 7) + byte
# Si bit 128 está activo...
if byte > 127:
# Eliminación de 128 correspondiente a bit más significativo.
number = number - 128
return number, (i+1)*8
return 0, offset
def decode(encoded):
'''Decodifica una secuencia de bytes codificada en Variable Byte.
Args:
encoded (byte list): números codificados.
Returns:
numbers (int list): números decodificados.
'''
numbers = []
number = 0
for byte in encoded:
# number = 128 * number + byte
number = (number << 7) + byte
# Si bit 128 está activo...
if byte > 127:
# Eliminación de 128 correspondiente a bit más significativo.
numbers.append(number-128)
# Finalización de decode para número actual.
number = 0
return numbers
def main():
'''Prueba de funcionamiento de las funciones encode y decode.'''
print("Prueba de encode/decode de 1 millón de enteros en curso...")
# upper = 1000000
# numbers = sorted(set(list(random.sample(range(2, upper*2), upper))))
numbers = list(range(0, 1000000))
# Encode
# gaps = gapsencoder.encode(numbers)
start = time.time()
encoded = []
for number in numbers:
encoded += encode(number)
end = time.time()
encoded_time = end-start
# Decode
start = time.time()
decoded = decode(encoded)
end = time.time()
decoded_time = end-start
if numbers != decoded:
print(numbers[-5:], decoded[-5:])
print("ATENCIÓN: numbers != decoded.")
return
print("Encoded time: {0}".format(encoded_time))
print("Decoded time: {0}".format(decoded_time))
if __name__ == '__main__':
main()