This is the performance version of [this kata](https://www.codewars.com/kata/59afff65f1c8274f270020f5).

---

Imagine two rings with numbers on them. The inner ring spins clockwise and the outer ring spins anti-clockwise. We start with both rings aligned on 0 at the top, and on each move we spin each ring by 1. How many moves will it take before both rings show the same number at the top again?

The inner ring has integers from 0 to innerMax and the outer ring has integers from 0 to outerMax, where innerMax and outerMax are integers >= 1.

```
e.g. if innerMax is 2 and outerMax is 3 then after
1 move: inner = 2, outer = 1
2 moves: inner = 1, outer = 2
3 moves: inner = 0, outer = 3
4 moves: inner = 2, outer = 0
5 moves: inner = 1, outer = 1
Therefore it takes 5 moves for the two rings to reach the same number
Therefore spinningRings(2, 3) = 5
```
```
e.g. if innerMax is 3 and outerMax is 2 then after
1 move: inner = 3, outer = 1
2 moves: inner = 2, outer = 2
Therefore it takes 2 moves for the two rings to reach the same number
spinningRings(3, 2) = 2
```

---

Test input range:

- `100` tests with `1 <= innerMax, outerMax <= 10000`
- `400` tests with `1 <= innerMax, outerMax <= 2^48`

Difficulty: MEDIUM_HARD
Starter code: def spinning_rings(inner_max, outer_max):
	

Solutions:
def spinning_rings(inner_max, outer_max):
	p = inner_max + 1
	q = outer_max + 1
	move = 1
	while -move % p != move % q:
		if -move % p >= q:
			move = move // p * p + p - q + 1
		elif move % q >= p:
			move = move // q * q + q
		elif -move % p > move % q and (-move % p + move % q) % 2 == 0:
			move += (-move % p - move % q) // 2
		else:
			move = min((move - 1) // p * p + p, (move - 1) // q * q + q) + 1
	return move


def spinning_rings(inner_max, outer_max):
	i = inner_max + 1
	j = outer_max + 1
	x = 1
	while x < i * j:
		a = -x % i
		b = x % j
		if a == b:
			return x
		elif a > b:
			if a > j:
				x += a - j
			else:
				x += max((a - b) // 2, 1)
		elif b > a:
			if b > i:
				x += j - b
			else:
				x += max(min(j - b, a), 1)


def spinning_rings(im, om):
	(a, b, res, d) = (im, 1, 1, abs(om - im))
	while a != b:
		x = 1
		if a - b > 2:
			x = (a - b) // 2
		if a < b:
			x = min(a + 1, om - b + 1)
		if b == im + 1 or (om < im and a == im):
			x = d
		if a - b == 1:
			x = min(d, min(a, om - b))
		(a, b) = ((a - x) % (im + 1), (b + x) % (om + 1))
		res += x
	return res


def spinning_rings(inner_max, outer_max):
	inner = inner_max
	outer = 1
	moves = 1
	while inner != outer:
		if outer > inner_max:
			jump = outer_max + 1 - outer
		elif inner > outer_max:
			jump = inner - outer_max
		elif inner > outer:
			jump = (inner - outer + 1) // 2
		elif inner == outer_max + 1 - outer:
			jump = inner
		else:
			jump = min(inner + 1, outer_max + 1 - outer)
		outer = (outer + jump) % (outer_max + 1)
		inner = (inner - jump) % (inner_max + 1)
		moves += jump
	return moves


def spinning_rings(inner_max, outer_max):
	if inner_max == outer_max:
		if inner_max % 2:
			return (inner_max + 1) / 2
		return inner_max + 1
	if inner_max % 2:
		res = (inner_max + 1) / 2 if outer_max > (inner_max + 1) / 2 else (inner_max + 1 + (outer_max + 1) * ((inner_max + 1) // (outer_max + 1) - 1 + ((inner_max + 1) // (outer_max + 1) + 1) * (outer_max + 1) % 2)) / 2
		return res
	if outer_max < inner_max:
		if outer_max % 2:
			a = 2 * (inner_max + 1) - (inner_max + 1) % (outer_max + 1)
			return a if (inner_max + 1) % (outer_max + 1) > (outer_max + 1) / 2 else a - (outer_max + 1) / 2
		else:
			a = inner_max + 1 - (inner_max - outer_max) % (outer_max + 1)
			b = (inner_max + 1 - a) // 2
			c = (outer_max + 1 + a) % 2
			return inner_max - b + 1 if not c else (inner_max - outer_max + a) / 2
	if outer_max > inner_max:
		k = (outer_max + 1) // (inner_max + 1)
		a = (k + 1) * (inner_max + 1) + (outer_max + 1) % (inner_max + 1) / 2
		return a if not (outer_max + 1) % (inner_max + 1) % 2 else 2 * (outer_max + 1) - (outer_max - inner_max / 2) - ((outer_max + 1) % (inner_max + 1) + 1) / 2


def spinning_rings(inner_max, outer_max):
	i = 1
	while True:
		inner = -i % (inner_max + 1)
		outer = i % (outer_max + 1)
		if inner == outer:
			return int(i)
		elif inner < outer:
			i += inner + 1 if inner_max > outer_max else outer_max - outer + 1
		elif inner > outer_max:
			i += inner - outer_max
		else:
			mid = (inner + outer) / 2
			if mid % 1 == 0:
				i += mid - outer
			else:
				i += min(inner, outer_max - outer) + 1


def spinning_rings(inner_max, outer_max):
	i = inner_max
	o = 1
	moves = 1
	while i != o:
		if o > inner_max:
			jump = outer_max + 1 - o
		elif i > outer_max:
			jump = i - outer_max
		elif i > o:
			jump = (i - o + 1) // 2
		elif i == outer_max + 1 - o:
			jump = i
		else:
			jump = min(i + 1, outer_max + 1 - o)
		o = (o + jump) % (outer_max + 1)
		i = (i - jump) % (inner_max + 1)
		moves += jump
	return moves


def spinning_rings(innermax, outermax):
	if innermax > outermax:
		a = innermax
		b = 1
		c = 1
		if a > outermax and outermax * 2 < innermax:
			c += a - outermax
			b += (a - outermax) % (outermax + 1)
			if b > outermax:
				b = 0
			a = outermax
		while a != b:
			if a > outermax and c != b:
				temp = c
				c += a - outermax
				b = (b + (c - temp)) % (outermax + 1)
				a = outermax
			if a % 2 == b % 2:
				return c + (a - b) // 2
			elif a < b:
				c += a + 1
				b += (a + 1) % (outermax + 1)
				a = innermax
			elif a > b:
				c += outermax - b + 1
				a = a - (outermax - b + 1)
				b = 0
			if a == 0:
				a = innermax
			else:
				a -= 1
			if b == outermax:
				b = 0
			else:
				b += 1
			c += 1
		else:
			return c
	else:
		a = innermax
		b = 1
		c = 1
		if a % 2 != 0:
			return a // 2 + 1
		while a != b:
			if a % 2 == 1 and b % 2 == 1:
				return c + (a // 2 + 1)
			elif a > b and a % 2 == 0 and (b % 2 == 0):
				return c + (a - b) // 2
			else:
				c = c + a
				b = b + a
				a = 0
			if b > innermax:
				a = abs((a - (outermax - b)) % (innermax + 1))
				c += outermax - b
				b = outermax
			if a == 0:
				a = innermax
			else:
				a -= 1
			if b == outermax:
				b = 0
			else:
				b += 1
			c += 1
		else:
			return c


def spinning_rings(inner_max, outer_max):
	outer_ring = 0
	count = 1
	if inner_max > outer_max:
		while True:
			count += inner_max - outer_max
			inner_ring = outer_max
			outer_ring += count % (outer_max + 1)
			if (inner_ring - outer_ring) % 2 == 0:
				count += (inner_ring - outer_ring) // 2
				return count
			else:
				count += outer_max - outer_ring + 1
				inner_ring -= outer_ring
				if inner_ring % 2 == 0:
					count += inner_ring // 2
					return count
				else:
					dist = (inner_max + 1) // (outer_max + 1)
					steps = dist * (outer_max + 1)
					if inner_max % 2 == outer_max % 2:
						inner_ring = inner_max - steps
						count = steps + inner_ring // 2
						return count + 1
					elif (inner_max - steps - 1) % 2 == 0:
						inner_ring = inner_max - steps
						count = steps + inner_ring // 2
						return count + 1
					else:
						count = inner_max + (inner_max - outer_max) + 1
						outer_ring = count % (outer_max + 1)
						count += (outer_max - outer_ring) // 2
				return count + 1
	elif outer_max > inner_max:
		inner_ring = inner_max
		count = 1
		outer_ring = 1
		while True:
			if (inner_ring - outer_ring) % 2 == 0:
				count += (inner_ring - outer_ring) // 2
				return count
			else:
				count = outer_max
				outer_ring = 0
				inner_ring -= count % (inner_max + 1)
				count += 1
				if inner_ring % 2 == 0:
					count += inner_ring // 2
					return count
				else:
					count += inner_ring + 1
					outer_ring += inner_ring + 1
					inner_ring = inner_max
					count += (inner_ring - outer_ring) // 2
				return count
	elif (outer_max - 1) % 2 == 0:
		return count + outer_max // 2