private function _parse_fraction($fraction, $offset = 0, $total)
{
if (strstr($fraction, '/')) {
$fraction = explode('/', $fraction);
if (isset($fraction[1]) && $fraction[1] > 0) {
$p = $fraction[1];
// the default number of partitions
$start = 0;
// index of the first partition
$end = $fraction[0];
// index of the last partition
// do we have an offset?
if ($offset) {
if (strstr($offset, '/')) {
// we were passed a fraction
$offset = explode('/', $offset);
} elseif (intval($offset) === $offset) {
// we were passed an integer, convert to a fraction of the total
$offset = array($offset, $total);
}
if (isset($offset[1]) && $offset[1] > 0) {
// do the denominators match?
if ($offset[1] !== $fraction[1]) {
// no, find the least common denominator for those numbers
$p = $this->_lcd(array($offset[1], $fraction[1]));
// multiply the numerators accordingly
$offset[0] = $p / $offset[1] * $offset[0];
$fraction[0] = $p / $fraction[1] * $fraction[0];
}
// update indexes of start/end partitions
$start = $offset[0];
$end = $start + $fraction[0];
} else {
$offset = 0;
}
}
// partition a temporary list
$partlen = floor($total / $p);
$partrem = $total % $p;
$partition = array();
$mark = 0;
$list = array_fill(0, $total, 0);
for ($px = 0; $px < $p; $px++) {
$incr = $px < $partrem ? $partlen + 1 : $partlen;
$partition[$px] = array_slice($list, $mark, $incr);
$mark += $incr;
}
unset($list);
$i = $start;
$index = 0;
while ($i < $end) {
if (isset($partition[$i])) {
$index += count($partition[$i]);
} else {
break;
}
$i++;
}
return $index;
}
} else {
return (int) $fraction;
}
}