blob: 89bf8d378cfcc983fff04e49683666a1a52ea819 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.numbers.complex;
/**
* Computation of the {@code n}-th roots of unity.
*/
public class RootsOfUnity {
/** 2 * π */
private static final double TWO_PI = 2 * Math.PI;
/** Number of roots of unity. */
private final int omegaCount;
/** The roots. */
private final Complex[] omega;
/**
* {@code true} if the constructor was called with a positive
* value of its argument {@code n}.
*/
private final boolean isCounterClockwise;
/**
* Computes the {@code n}-th roots of unity.
*
* The roots are stored in an array
* {@code omega[]}, such that {@code omega[k] = w ^ k}, where
* {@code k = 0, ..., n - 1}, {@code w = exp(2 * pi * i / n)} and
* {@code i = sqrt(-1)}.
*
* <p>{@code n} can be positive of negative ({@code abs(n)} is always
* the number of roots of unity):</p>
* <ul>
* <li>If {@code n > 0}, then the roots are stored in counter-clockwise order.</li>
* <li>If {@code n < 0}, then the roots are stored in clockwise order.</li>
* </ul>
*
* @param n The (signed) number of roots of unity to be computed.
* @throws IllegalArgumentException if {@code n == 0}?
*/
public RootsOfUnity(int n) {
if (n == 0) {
throw new IllegalArgumentException("Zero-th root");
}
omegaCount = Math.abs(n);
isCounterClockwise = n > 0;
omega = new Complex[omegaCount];
final double t = TWO_PI / omegaCount;
final double cosT = Math.cos(t);
final double sinT = Math.sin(t);
double previousReal = 1;
double previousImag = 0;
omega[0] = new Complex(previousReal, previousImag);
for (int i = 1; i < omegaCount; i++) {
final double real = previousReal * cosT - previousImag * sinT;
final double imag = previousReal * sinT + previousImag * cosT;
omega[i] = isCounterClockwise ?
new Complex(real, imag) :
new Complex(real, -imag);
previousReal = real;
previousImag = imag;
}
}
/**
* Returns {@code true} if {@link #RootsOfUnity(int)} was called with a
* positive value of its argument {@code n}.
* If {@code true}, then the imaginary parts of the successive roots are
* {@link #getRoot(int) returned} in counter-clockwise order.
*
* @return {@code true} if the roots of unity are stored in
* counter-clockwise order.
*/
public boolean isCounterClockwise() {
return isCounterClockwise;
}
/**
* Gets the {@code k}-th among the computed roots of unity.
*
* @param k Index of the requested value.
* @return the {@code k}-th among the {@code N}-th root of unity
* where {@code N} is the absolute value of the argument passed
* to the constructor.
* @throws IndexOutOfBoundsException if {@code k} is out of range.
*/
public Complex getRoot(int k) {
return omega[k];
}
/**
* Gets the number of roots of unity.
*
* @return the number of roots of unity.
*/
public int getNumberOfRoots() {
return omegaCount;
}
}