(self, modulus: int, residue: int)
| 96 | ) |
| 97 | |
| 98 | def modulo(self, modulus: int, residue: int) -> AxisRange: |
| 99 | residue %= modulus |
| 100 | rhs = (residue - self.offset) % modulus |
| 101 | g = _gcd(self.stride, modulus) |
| 102 | if rhs % g != 0: |
| 103 | raise ExecContextError( |
| 104 | f"modulo filter produces empty range: {self.offset} + {self.stride} * i" |
| 105 | f" == {residue} mod {modulus}" |
| 106 | ) |
| 107 | reduced_stride = self.stride // g |
| 108 | reduced_rhs = rhs // g |
| 109 | reduced_modulus = modulus // g |
| 110 | period = reduced_modulus |
| 111 | i0 = (reduced_rhs * _mod_inverse(reduced_stride, reduced_modulus)) % reduced_modulus |
| 112 | if i0 >= self.extent: |
| 113 | raise ExecContextError( |
| 114 | f"modulo filter produces empty range: {self.offset} + {self.stride} * i" |
| 115 | f" == {residue} mod {modulus}" |
| 116 | ) |
| 117 | return AxisRange( |
| 118 | extent=(self.extent - 1 - i0) // period + 1, |
| 119 | offset=self.offset + self.stride * i0, |
| 120 | stride=self.stride * period, |
| 121 | ) |
| 122 | |
| 123 | |
| 124 | @dataclass(frozen=True) |
no test coverage detected