You are correct, this is another error in this algorithm (complete code in a github archive, are there more official online sources?). It is clearly stated in the header comments that
% v is a column m-vector with v(1) = 1 and beta is a scalar such
% that P = I - beta*v*v' is orthogonal and Px = norm(x)*e1.
and in the general case beta
is computed as
beta = 2*v(1)^2/(sigma+v(1)^2);
v = v/v(1);
according to the documented intent. When testing this there apparently were no tests for trivial cases. On the other hand, getting sigma == 0
in the usual situation of a call from the middle of some numerical algorithm has probability zero.
The more serious error is in the algorithm design, in the choice of the construction of the reflection normal v
as a continuous vector field on the punctured sphere, excepting the "north" pole, as done with the first special case.
The question of course remains if that makes sense at all. Comparing a floating point value with $0$ in a numerical algorithm smells of bad design. If one has to avoid a singularity in one point, then it is to be expected that results close to that singularity are ill-behaved, with a dramatic loss in accuracy or the magnification of floating-point noise to the level of the intended results.
The stated aim is to get the first component of the reflected vector to be positive. The general construction is to find one of the two bisectors of the lines along the given vectors $\vec x$, and some unit vector $\vec e$, typically $\vec e=\vec e_1=(1,0,…,0)^T$,
$$
\vec v = \frac{\pm\|\vec x\|\vec e+\vec x}{\bigl\|\pm\|\vec x\|\vec e+\vec x\bigr\|}
=\frac{\pm\|\vec x\|\vec e+\vec x}{\sqrt{2\|\vec x\|(\|\vec x\|\pm\vec e^T\vec x)}}.
$$
The recommendation for numerical stability is to take the variant that makes the denominator largest. This switches the variants at the equator (normal plane to $\vec e$), this switch is a jump by $90°$ in the direction.
With $\vec e=\vec e_1$, the reflected vector has as first component
\begin{align}
x_{1,\rm reflect}
&=x_1-2\frac{(\pm\|\vec x\|+x_1)\|\vec x\|(\pm x_1+\|\vec x\|)}{2\|\vec x\|(\|\vec x\|\pm x_1)}
\\&=\mp \|\vec x\|
\end{align}
So to always end up with a positive number one would have to chose the lower sign variant, with the special case where that does not work. This can even be done in a numerically stable way when $\vec x\approx \|\vec x\|\vec e_1$, as by binomial extension
$$
x_1-\|\vec x\|=\frac{-(\|\vec x\|^2-x_1^2)}{\|\vec x\|+x_1}
=-\frac{\|\vec x_{2:n}\|^2}{\|\vec x\|+x_1}
$$
Why would that be bad? Explore the reflector construction for $\vec x=\pmatrix{1\\\bar x}$ with $\|\bar x\|\sim\mu=10^{-16}$ some quasi-random accumulation of rounding errors from previous computational steps. Then using the "bad choice" the reflector unit normal will be close to $\pmatrix{-\|\bar x\|/2\\\bar x/\|\bar x\|}$. Thus a small error in the input leads to a large difference in the result, a random point on the equator. This kind of unpredictability, "catastrophic" error magnification, is usually unwanted in stable numerical algorithms.
The "good choice" would always result in a reflector normal close to the north unit vector $\pmatrix{1\\0}$, this kind of dependency is what is actually desired.
Now one could ask what about points on the equator under the "good choice", then both the midpoint to the north pole and the midpoint to the south pole are equally good. While it is true that under slight perturbations one of the two is selected quasi randomly, the result still stays close to one of these two possibilities, this is still numerically stable under a slight extension of this idea.
pinv(pinv(A))-A
increased by a factor of $4$ (or more?). Extreme cases likex = [1e+10, 1e-10]
gave grave errors in the first Lapack versions using this method (v 3.2, 2009), but that was corrected with the binomial trick some time later (and the universal use of LARFP was rolled back, making ...P versions of the routines using it). – Lutz Lehmann Dec 07 '22 at 11:33