stats/src/main/java/io/airlift/stats/ExponentiallyDecayingSample.java
private void rescale(long now, long next)
    {
        if (nextScaleTime.compareAndSet(next, now + RESCALE_THRESHOLD)) {
            lockForRescale();
            try {
                final long oldStartTime = startTime;
                this.startTime = tick();
                final ArrayList<Double> keys = new ArrayList<>(values.keySet());
                for (Double key : keys) {
                    final Long value = values.remove(key);
                    values.put(key * exp(-alpha * (startTime - oldStartTime)), value);
                }
            }
            finally {
                unlockForRescale();
            }
        }
    }
private void rescale(long now, long next)
    {
        if (nextScaleTime.compareAndSet(next, now + RESCALE_THRESHOLD)) {
            lockForRescale();
            try {
                final long oldStartTime = startTime;
                this.startTime = tick();
                final ArrayList<Double> keys = new ArrayList<>(values.keySet());
                for (Double key : keys) {
                    final Long value = values.remove(key);
                    values.put(key * exp(-alpha * (startTime - oldStartTime)), value);
                }
            }
            finally {
                unlockForRescale();
            }
        }
    }
private void rescale ( long now , long next ) { if ( nextScaleTime . compareAndSet ( next , now + RESCALE_THRESHOLD ) ) { lockForRescale ( ) ; try { final long oldStartTime = startTime ; this . startTime = tick ( ) ; final ArrayList < Double > keys = new ArrayList <> ( values . keySet ( ) ) ; for ( Double key : keys ) { final Long value = values . remove ( key ) ; values . put ( key * exp ( - alpha * ( startTime - oldStartTime ) ) , value ) ; } } finally { unlockForRescale ( ) ; } } }
/* "A common feature of the above techniques—indeed, the key technique that
allows us to track the decayed weights efficiently—is that they maintain
counts and other quantities based on g(ti − L), and only scale by g(t − L)
at query time. But while g(ti −L)/g(t−L) is guaranteed to lie between zero
and one, the intermediate values of g(ti − L) could become very large. For
polynomial functions, these values should not grow too large, and should be
effectively represented in practice by floating point values without loss of
precision. For exponential functions, these values could grow quite large as
new values of (ti − L) become large, and potentially exceed the capacity of
common floating point types. However, since the values stored by the
algorithms are linear combinations of g values (scaled sums), they can be
rescaled relative to a new landmark. That is, by the analysis of exponential
decay in Section III-A, the choice of L does not affect the final result. We
can therefore multiply each value based on L by a factor of exp(−α(L′ − L)),
and obtain the correct value as if we had instead computed relative to a new
landmark L′ (and then use this new L′ at query time). This can be done with
a linear pass over whatever data structure is being used."
/ * A common feature of the above techniques—indeed the key technique that allows us to track the decayed weights efficiently—is that they maintain counts and other quantities based on g ( ti − L ) and only scale by g ( t − L ) at query time . But while g ( ti −L ) / g ( t−L ) is guaranteed to lie between zero and one the intermediate values of g ( ti − L ) could become very large . For polynomial functions these values should not grow too large and should be effectively represented in practice by floating point values without loss of precision . For exponential functions these values could grow quite large as new values of ( ti − L ) become large and potentially exceed the capacity of common floating point types . However since the values stored by the algorithms are linear combinations of g values ( scaled sums ) they can be rescaled relative to a new landmark . That is by the analysis of exponential decay in Section III - A the choice of L does not affect the final result . We can therefore multiply each value based on L by a factor of exp ( −α ( L′ − L )) and obtain the correct value as if we had instead computed relative to a new landmark L′ ( and then use this new L′ at query time ) . This can be done with a linear pass over whatever data structure is being used .