質問

I have the following structures in my code:

class Interval {
    public $start, $end;
}

class Period {
    public $interval, $period;
}

They represent a simple and repeating interval, respectively. For example:

**** // This is a simple interval [0, 4].
****__****__**** // This is "repeating interval" with period = 2 (each underline means pause between intervals)

So period is an infinite set of intervals. The "distance" (or pause) between each of them is constant.

I need a function that accepts an arbitrary interval and period and says whether this interval is inside period or not. "Inside" means that given interval is inside any of intervals in period.

function interval_inside_period(Interval $interval, Period $period) {
  return is_inside ? true : false;
}

$period = new Period(new Interval(0, 4), 10); 
// The first 3 intervals in this Period are [0, 4], [14, 18] and [28, 32]
// Like: ****__________****__________****
interval_inside_period(new Interval(15, 16), $period); // === true, is inside [14, 18]
interval_inside_period(new Interval(29, 32), $period); // === true, is inside [28, 32]
interval_inside_period(new Interval( 3,  5), $period); // === false, overlaps but is not inside
interval_inside_period(new Interval(17, 29), $period); // === false, overlaps but is not inside
interval_inside_period(new Interval(11, 12), $period); // === false
interval_inside_period(new Interval(20, 27), $period); // === false

The problem is that due to the lack of math experience I have no idea how to implement such function. I've thought about wave functions, specially about rectangular periodic function but i have no idea how to describe Period with such function.

A simple Period with equal length and periodicity can be described by Square wave function:

$square_period = new Period(new Interval(0, 2), 2);
// __**__**__**__**
// This function describes such Period.
function is_square_period($n) {
    return ($n >= 0 && ($n / 2) % 2) == 0 ? 1 : 0;
}

This approach gives opportunity to find if any integer $n lays inside Period or not. But I don't know if this can be used to solve the problem.

Any ideas? Thanks in advance.

役に立ちましたか?

解決

Let's see... The offset between two consecutive intervals is $start + $end + $period. The start of interval k is therefore at k * ($start + $end + $period) + $start. By dividing x from a given Interval (new Interval(x, y)) by $start + $end + $period we can calculate our k:

// this is should be integer division...
$k = ($interval->start - $period->interval->start)
    / ($period->interval->start + $period->interval->end + $period->period);

Now we can calculate the bounds of interval k and check if the given interval is inside of it.

$kStart = $k * (
        $period->interval->start + $period->interval->end + $period->period
    ) + $period->interval->start;
$kEnd = $kStart + ($period->interval->end - $period->interval->start);

return $kStart <= $interval->start && interval->end <= $kEnd;

This yields the following with the period and the first interval from your question:

$k = (15 - 0) / (0 + 4 + 10) = 15 / 14 = 1
$kStart = 1 * (0 + 4 + 10) + 0 = 1 * 14 + 0 = 14
$kEnd = 14 + (4 - 0) = 18

return (14 <= 15 && 16 <= 18) // true

The values for the remaining intervals are:

iStart | iEnd | k | kStart | kEnd | result
-------+------+---+--------+------+-------
    29 |   32 | 2 |     28 |   32 | true
     3 |    5 | 0 |      0 |    4 | false
    17 |   29 | 1 |     14 |   18 | false
    11 |   12 | 0 |      0 |    4 | false
    20 |   27 | 1 |     14 |   18 | false
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top