Ruby, 68
Lambda function takes complex number as argument, returns complex number.
->z{k=1
4.times{z*=?i.to_c
x,y=z.rect
y*y>=x*x&&y<-x&&(z+=k;k=0)}
z}
We rotate the point through 90 degrees 4 times by multiplying by i
. It therefore passes through all 4 quadrants, and would be returned unchanged - except for the fact we modify it when it is in a specific one of them. The fact it is always modified in the same quadrant simplifies the modification.
It is easiest to follow if we alter it z
when it is in the righthand quadrant. in this case we need to increase the y coordinate by 1 (i.e add i
to z
.)
We check x.abs>=y.abs
by comparing the squares of x
and y
. This tells us the point is in the righthand or lefthand quadrant, not top or bottom. To check it is in fact in the righthand quadrant we further check that x>y
(strictly greater because we want to exclude the case x=y
which belongs to the "top" quadrant.) Where this is true we add i
to z
.
For golfing reasons, adding i
is not desirable. Instead we modifiy the number when it is in the bottom quadrant, in which case we have to add 1 to the x
coordinate (add 1 to z
.) In this case we test that y*y>=x*x
to check it is in the top or bottom quadrant. To further ensure it is in the bottom quadrant we need to check y<-x
(strictly excluding the case of the bottom right corner where y=-x
.)
An advantage of this check is there is no special case for the coordinate 0,0. Unfortunately it was found that moving the point can shift it to a different quadrant and this means that a second movement must be suppressed should that quadrant be checked again, which probably negates the advantage.
Example 1
Input 95,-12
Rotate 90deg 12,95
Rotate 90deg -95,12
Rotate 90deg -12,-95
Rotate 90deg 95,-12
y.abs>=x.abs=TRUE, y<-x=TRUE, increase x 95,-11
The check and alteration of the coordinate is done AFTER the rotation.
Thus in this case it gets done in the 4th iteration of the loop, not the 1st.
If the code were rewritten to do the check and alteration BEFORE the rotation,
it would be done in the 1st iteration instead of the 4th.
Example 2
Input -1,0
Rotate 90deg 0,-1
y.abs>=x.abs=TRUE, y<-x=TRUE, increase x 1,-1
Rotate 90deg 1,1
Rotate 90deg 1,-1
Rotate 90deg -1,-1
y.abs>=x.abs?=TRUE, y<-x=TRUE but DO NOT CHANGE x!
This is an unusual situation due to the fact that the first move caused the
point to advance by one quadrant. We do NOT want to move it again, for this
reason we need to set k to 0 the first time it is moved.
In test program
f=->z{k=1 #amount to be added to coordinate
4.times{z*=?i.to_c #iterate 4 times, rotating point by 90deg till it reaches the original orientation
x,y=z.rect #separate out x and y for testing
y*y>=x*x&&y<-x&&(z+=k;k=0)} #if y.abs>=x.abs and y negative and not equal -x, move the point and zero k.
z} #return z
puts f[Complex(0, 0)] # (0, 0)
puts f[Complex(1, 0)] # (1, 1)
puts f[Complex(1, 1)] # (0, 1)
puts f[Complex(0, 1)] # (-1, 1)
puts f[Complex(-1, 1)] # (-1, 0)
puts
puts f[Complex(-1, 0)] # (-1, -1)
puts f[Complex(-1, -1)] # (0, -1)
puts f[Complex(0, -1)] # (1, -1)
puts f[Complex(1, -1)] # (1, 0)
puts f[Complex(95, -12)] # (95, -11)
puts f[Complex(127, 127)] # (126, 127)
puts
puts f[Complex(-2, 101)] # (-3, 101)
puts f[Complex(-65, 65)] # (-65, 64)
puts f[Complex(-127, 42)] # (-127, 41)
puts f[Complex(-9, -9)] # (-8, -9)
puts f[Complex(126, -127)] # (127, -127)
puts f[Complex(105, -105)] # (105, -104)
Diagram
The following image shows (blue) the area where x*x>=y*y
, (yellow) the area where y<-x
and (green) the intersection of these, which is the region where the correct transformation is the addition of 1 to z
.