/* XOWA: the XOWA Offline Wiki Application Copyright (C) 2012 gnosygnu@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package gplx.dbs.percentiles; import gplx.*; import gplx.dbs.*; public class Percentile_rng { private long total_max; private int total_needed; private int score_max, score_len_max; private long prv_time; public int Score_bgn() {return score_bgn;} private int score_bgn; public int Score_end() {return score_end;} private int score_end; public int Score_len() {return score_len;} private int score_len; public int Found_rdr() {return found_rdr;} private int found_rdr; public int Found_all() {return found_all;} private int found_all; public int Elapsed() {return elapsed;} private int elapsed; public Percentile_rng Init(long total_max, int score_max) { this.total_max = total_max; this.score_max = score_max; this.score_len_max = score_max / 20; // limit to 5% return this; } public void Select_init(int total_needed, int prv_score_bgn, int prv_score_len, int score_len_adj) { this.total_needed = total_needed; this.found_all = 0; this.prv_time = gplx.core.envs.Env_.TickCount(); int score_unit = Calc_score_unit(total_needed, total_max, score_max); if (prv_score_bgn == Score_null) { score_len = score_unit + (score_unit * score_len_adj); score_bgn = score_max; Rng_len_(Bool_.Y); } else { score_len = prv_score_len; score_bgn = prv_score_bgn; score_end = score_bgn + score_len; } } public void Update(int found_rdr) { this.found_rdr = found_rdr; this.found_all += found_rdr; // calc rng_multiplier based on found_rdr and total_needed; EX: 100=total_needed; 10=found_rdr; 40=found_all -> 6=rng_multiplier; (100 - 40 / 10) int rng_multiplier = 1; if (found_rdr == 0) { rng_multiplier = 4; } else { int total_remaining = total_needed - found_all; rng_multiplier = total_remaining == 0 ? 1 : Math_.Ceil_as_int(total_remaining / found_rdr); } // calc new score_len int new_score_len = score_len * rng_multiplier; if (new_score_len < 1) new_score_len = score_len; else if (new_score_len > score_len_max) new_score_len = score_len_max; score_len = new_score_len; Rng_len_(Bool_.N); // update times long new_time = gplx.core.envs.Env_.TickCount(); this.elapsed = Int_.Subtract_long(new_time, prv_time); prv_time = new_time; } private void Rng_len_(boolean first) { score_end = score_bgn + (first ? 1 : 0); // + 1 to include rows with scores at max; EX: > 999,998 AND < 1,000,001 score_bgn = score_end - score_len; if (score_bgn < 0) score_bgn = 0; // make sure score is not negative } @gplx.Internal protected static int Calc_score_unit(int total_needed, long total_max, int score_max) {// TEST: int rv = (int)Math_.Ceil(Math_.Div_safe_as_double(total_needed, Math_.Div_safe_as_double(total_max, score_max))); // EX: 100 needed / (16 M / 1 M) -> 7 units to fill 100 if (rv > score_max) rv = score_max; // never allow score_unit to be > score_max; occurs when total_needed > total_max; EX: 50 needed; 10 available return rv; } public static final int Score_null = -1; }