zlarfgp function

void zlarfgp(
  1. int N,
  2. Box<Complex> ALPHA,
  3. Array<Complex> X_,
  4. int INCX,
  5. Box<Complex> TAU,
)

Implementation

void zlarfgp(
  final int N,
  final Box<Complex> ALPHA,
  final Array<Complex> X_,
  final int INCX,
  final Box<Complex> TAU,
) {
  final X = X_.having();
  const TWO = 2.0, ONE = 1.0, ZERO = 0.0;
  int J, KNT;
  double ALPHI, ALPHR, BETA, BIGNUM, EPS, SMLNUM, XNORM;
  Complex SAVEALPHA;

  if (N <= 0) {
    TAU.value = Complex.zero;
    return;
  }

  EPS = dlamch('Precision');
  XNORM = dznrm2(N - 1, X, INCX);
  ALPHR = ALPHA.value.real;
  ALPHI = ALPHA.value.imaginary;

  if (XNORM <= EPS * ALPHA.value.abs() && ALPHI == ZERO) {
    // H  =  [1-alpha/abs(alpha) 0; 0 I], sign chosen so ALPHA >= 0.
    if (ALPHR >= ZERO) {
      // When TAU == ZERO, the vector is special-cased to be
      // all zeros in the application routines.  We do not need
      // to clear it.
      TAU.value = Complex.zero;
    } else {
      // However, the application routines rely on explicit
      // zero checks when TAU != ZERO, and we must clear X.
      TAU.value = TWO.toComplex();
      for (J = 1; J <= N - 1; J++) {
        X[1 + (J - 1) * INCX] = Complex.zero;
      }
      ALPHA.value = -ALPHA.value;
    }
  } else {
    // general case
    BETA = sign(dlapy3(ALPHR, ALPHI, XNORM), ALPHR);
    SMLNUM = dlamch('S') / dlamch('E');
    BIGNUM = ONE / SMLNUM;

    KNT = 0;
    if (BETA.abs() < SMLNUM) {
      // XNORM, BETA may be inaccurate; scale X and recompute them
      do {
        KNT++;
        zdscal(N - 1, BIGNUM, X, INCX);
        BETA *= BIGNUM;
        ALPHI *= BIGNUM;
        ALPHR *= BIGNUM;
      } while ((BETA.abs() < SMLNUM) && (KNT < 20));

      // New BETA is at most 1, at least SMLNUM
      XNORM = dznrm2(N - 1, X, INCX);
      ALPHA.value = Complex(ALPHR, ALPHI);
      BETA = sign(dlapy3(ALPHR, ALPHI, XNORM), ALPHR);
    }
    SAVEALPHA = ALPHA.value;
    ALPHA.value += BETA.toComplex();
    if (BETA < ZERO) {
      BETA = -BETA;
      TAU.value = -ALPHA.value / BETA.toComplex();
    } else {
      ALPHR = ALPHI * (ALPHI / ALPHA.value.real);
      ALPHR += XNORM * (XNORM / ALPHA.value.real);
      TAU.value = Complex(ALPHR / BETA, -ALPHI / BETA);
      ALPHA.value = Complex(-ALPHR, ALPHI);
    }
    ALPHA.value = zladiv(Complex.one, ALPHA.value);

    if (TAU.value.abs() <= SMLNUM) {
      // In the case where the computed TAU ends up being a denormalized number,
      // it loses relative accuracy. This is a BIG problem. Solution: flush TAU
      // to ZERO (or TWO or whatever makes a nonnegative real number for BETA).
      ALPHR = SAVEALPHA.real;
      ALPHI = SAVEALPHA.imaginary;
      if (ALPHI == ZERO) {
        if (ALPHR >= ZERO) {
          TAU.value = Complex.zero;
        } else {
          TAU.value = TWO.toComplex();
          for (J = 1; J <= N - 1; J++) {
            X[1 + (J - 1) * INCX] = Complex.zero;
          }
          BETA = (-SAVEALPHA).real;
        }
      } else {
        XNORM = dlapy2(ALPHR, ALPHI);
        TAU.value = Complex(ONE - ALPHR / XNORM, -ALPHI / XNORM);
        for (J = 1; J <= N - 1; J++) {
          X[1 + (J - 1) * INCX] = Complex.zero;
        }
        BETA = XNORM;
      }
    } else {
      // This is the general case.
      zscal(N - 1, ALPHA.value, X, INCX);
    }

    // If BETA is subnormal, it may lose relative accuracy
    for (J = 1; J <= KNT; J++) {
      BETA *= SMLNUM;
    }
    ALPHA.value = BETA.toComplex();
  }
}