Ho un ampio set di valori (diciamo 1M voci) dove devo applicare un algoritmo smoothing esponenziale , ma solo incrementando un valore alla volta (tutto altri decadono a zero). L'implementazione banale sarebbe (pseudo-codice):
function smooth_once(index, x):
// Decay everything
for s in s_vec:
s = s * (1 - alpha)
// Only increase one value, for the other x=0
s_vec[index] += alpha * x
function get_s(index):
return s_vec[index]
Questo è piuttosto lento, poiché ogni elemento di s_vec
deve essere scansionato ad ogni iterazione, mentre solo uno deve essere incrementato. Inoltre, ho solo bisogno di controllare alcuni valori da s_vec
di tanto in tanto (molto meno frequentemente della frequenza con cui viene chiamato smooth_once
).
Nota: la sequenza di levigatura e lettura è imprevedibile ed è solitamente interlacciata, ad esempio:
smooth_once(6573, 1.23)
get_s(8892)
smooth_once(3345, 2.45)
smooth_once(6874, 1.10)
get_s(3345)
get_s(1254)
...etc...
Per accelerare ciò, stavo pensando di moltiplicare il valore x
di un fattore ( scale
) che viene moltiplicato ogni volta e dividendo tutto quando il fattore diventa troppo grande. Fondamentalmente, questo si riduce a ridimensionare tutto con un fattore di incremento esponenziale .
scale = 1
k = 1 / (1 - alpha)
function optimized_smooth(index, x):
// Rescale everything
scale = scale * k
if scale > scale_max:
// Switch back scale to 1
for s in s_vec:
s = s / scale
scale = 1
s_vec[index] = v + alpha * x * scale
function get_s(index):
// Scale back for reading
return s_vec[index] / scale
IMHO questo sarebbe molto più veloce (supponendo che k non sia troppo grande), poiché devi solo scansionare s_vec
quando l'overflow della scala e ridimensionare l'intero array.
- Cosa ne pensi di questo metodo?
- È già noto e ha un nome?
- Oltre a perdere qualche bit di precisione sui valori (a seconda di beta_max), vedi qualche svantaggio?
Addendum. Un piccolo programma dimostrativo mostra che entrambi gli algoritmi finiscono con lo stesso risultato su una sequenza controllata di indici uniformi.