/*
* Util.java
* (FScape)
*
* Copyright (c) 2001-2016 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU General Public License v3+
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de
*
*
* Changelog:
* 17-Jun-07 extended
*/
package de.sciss.fscape.util;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Util
{
/**
* Checks if a certain int value is an element of a
* specific int array.
*
* @param val value to seek for in array
* @param array may be any size, may not be null
* @return true, if value is an element of array
*/
public static boolean isValueInArray( int val, int[] array )
{
for( int i = 0; i < array.length; i++ ) {
if( array[ i ] == val ) return true;
}
return false;
}
/**
* Checks if a certain String value is an element of a
* specific String array.
*
* @param val value to seek for in array
* @param array may be any size, may not be null
* @return true, if value is an element of array
*/
public static boolean isValueInArray( String val, String[] array )
{
for( int i = 0; i < array.length; i++ ) {
if( array[ i ].equals( val )) return true;
}
return false;
}
/**
* Zirkulaere Buffer-Rotation
*
* @param a zu rotierender puffer
* @param len von a
* @param buf zwischenpuffer; laenge muss mind. abs( shift ) sein!
* darf null sein
* @param shift bewegungsumfang
*/
public static void rotate( float[] a, int len, float[] buf, int shift )
{
if( buf == null ) {
buf = new float[ shift ];
}
if( shift < 0 ) {
shift = -shift;
System.arraycopy( a, 0, buf, 0, shift );
System.arraycopy( a, shift, a, 0, len - shift );
System.arraycopy( buf, 0, a, len - shift, shift );
} else if( shift > 0 ) {
System.arraycopy( a, len - shift, buf, 0, shift );
System.arraycopy( a, 0, a, shift, len - shift );
System.arraycopy( buf, 0, a, 0, shift );
}
}
/**
* Polynom-Interpolation (oder Extrapolation)
*
* @param xa bekannte zu benutzende Stellen
* @param ya Werte zu xa
* @param n Interpolationsgrad
* @param x Stelle, die berechnet werden soll
* @return interpolierter Wert
*
* taken + adapted from Numerical Recipes in C
*/
public static float polyInterpolate( float xa[], float ya[], int n, float x )
{
int i, m, ns;
float y;
float den, minDif, dif, ho, hp, w, rescue;
float[] c, d;
minDif = Math.abs( x - xa[ 1 ]);
c = new float[ n ];
d = new float[ n ];
// Here we find the index ns of the closest table entry,
for( i = 0, ns = 0; i < n; i++) {
dif = Math.abs( x - xa[ i ]);
if( dif < minDif) {
ns = i;
minDif = dif;
}
c[ i ] = ya[ i ]; // ...and initialize the tableau of c's and d's.
d[ i ] = ya[ i ];
}
rescue = ya[ ns ];
y = rescue; // This is the initial approximation to y.
// For each column of the tableau,
for( m = 1; m < n; m++ ) {
// ...we loop over the current c's and d's and update them.
for( i = 0; i < (n - m); i++ ) {
ho = xa[ i ] - x;
hp = xa[ i+m ] - x;
w = c[ i+1 ] - d[ i ];
den = ho - hp;
// This error can occur only if two input xa's are (to within roundoff) identical.
if( den == 0.0f ) return rescue;
den = w / den;
d[ i ] = hp * den; // Here the c's and d's are updated.
c[ i ] = ho * den;
}
// After each column in the tableau is completed, we decide which correction, c or d,
// we want to add to our accumulating value of y, i.e., which path to take through the
// tableau|forking up or down. We do this in such a way as to take the most \straight
// line" route through the tableau to its apex, updating ns accordingly to keep track of
// where we are. This route keeps the partial approximations centered (insofar as possible)
// on the target x. Thelastdy added is thus the error indication.
y += ((ns << 1) < (n - m)) ? c[ ns ] : d [ --ns ];
}
return y;
}
/**
* Eindimensionales Array loeschen
*/
public static void clear( float[] a )
{
for( int i = 0; i < a.length; i++ ) {
a[ i ] = 0.0f;
}
}
/** Fills a two-dimensional array with a constant value. */
public static void fill(float[][] a, int off, int len, float value) {
final int stop = off + len;
for (float[] ch : a) {
for (int j = off; j < stop; j++) {
ch[j] = value;
}
}
}
/** Fills a two-dimensional array with a constant value. */
public static void fill(double[][] a, int off, int len, double value) {
final int stop = off + len;
for (double[] ch : a) {
for (int j = off; j < stop; j++) {
ch[j] = value;
}
}
}
/**
* Eindimensionales Array loeschen
*/
public static void clear( double[] a )
{
for( int i = 0; i < a.length; i++ ) {
a[ i ] = 0.0;
}
}
/**
* Eindimensionales Array zu einem zweiten addieren
*/
public static void add( float[] src, int srcOff, float[] dest, int destOff, int length )
{
final int stop = srcOff + length;
while( srcOff < stop ) {
dest[ destOff++ ] += src[ srcOff++ ];
}
}
/**
* Zweidimensionales Array zu einem zweiten addieren
*/
public static void add( float[][] src, int srcOff, float[][] dest, int destOff, int length )
{
final int stop = srcOff + length;
float[] b, c;
for( int i = 0; i < src.length; i++ ) {
b = src[ i ];
c = dest[ i ];
for( int j = srcOff, k = destOff; j < stop; j++, k++ ) {
c[ k ] += b[ j ];
}
}
}
/**
* Konstante in eindimensionales Array addieren
*/
public static void add( float[] a, int off, int length, float val )
{
final int stop = off + length;
while( off < stop ) a[ off++ ] += val;
}
/**
* Konstante in zweidimensionales Array addieren
*/
public static void add( float[][] a, int off, int length, float val )
{
final int stop = off + length;
float[] b;
for( int i = 0; i < a.length; i++ ) {
b = a[ i ];
for( int j = off; j < stop; j++ ) {
b[ j ] += val;
}
}
}
/**
* Eindimensionales Array von einem zweiten subtrahieren
*/
public static void sub( float[] src, int srcOff, float[] dest, int destOff, int length )
{
final int stop = srcOff + length;
while( srcOff < stop ) {
dest[ destOff++ ] -= src[ srcOff++ ];
}
}
/**
* Eindimensionales Array in eine zweites multiplizieren
*/
public static void mult( float[] src, int srcOff, float[] dest, int destOff, int length )
{
final int stop = srcOff + length;
while( srcOff < stop ) {
dest[ destOff++ ] *= src[ srcOff++ ];
}
}
/**
* Eindimensionales Array in ein zweites zweidimensionales multiplizieren
*/
public static void mult( float[] src, int srcOff, float[][] dest, int destOff, int length )
{
final int stop = srcOff + length;
float[] b;
for( int i = 0; i < dest.length; i++ ) {
b = dest[ i ];
for( int j = srcOff, k = destOff; j < stop; j++, k++ ) {
b[ k ] *= src[ j ];
}
}
}
/**
* Zweidimensionales Array in ein zweites multiplizieren
*/
public static void mult( float[][] src, int srcOff, float[][] dest, int destOff, int length )
{
final int stop = srcOff + length;
float[] b, c;
for( int i = 0; i < dest.length; i++ ) {
b = dest[ i ];
c = src[ i ];
for( int j = srcOff, k = destOff; j < stop; j++, k++ ) {
b[ k ] *= c[ j ];
}
}
}
/**
* Eindimensionales Array mit skalar multiplizieren
*/
public static void mult( float[] a, int off, int length, float gain )
{
final int stop = off + length;
while( off < stop ) {
a[ off++ ] *= gain;
}
}
/**
* Zweidimensionales Array mit skalar multiplizieren
*/
public static void mult( float[][] a, int off, int length, float gain )
{
final int stop = off + length;
float[] b;
for( int i = 0; i < a.length; i++ ) {
b = a[ i ];
for( int j = off; j < stop; j++ ) {
b[ j ] *= gain;
}
}
}
/**
* Zweidimensionales Array loeschen
*/
public static void clear( float[][] a )
{
float[] b;
for( int i = 0; i < a.length; i++ ) {
b = a[ i ];
for( int j = 0; j < b.length; j++ ) {
b[ j ] = 0.0f;
}
}
}
/** Clear two dimensional array. */
public static void clear(double[][] a) {
double[] b;
for (int i = 0; i < a.length; i++) {
b = a[i];
for (int j = 0; j < b.length; j++) {
b[j] = 0.0;
}
}
}
/**
* Zweidimensionales Array loeschen
*/
public static void clear( float[][] a, int off, int length )
{
final int stop = off + length;
float[] b;
for( int i = 0; i < a.length; i++ ) {
b = a[ i ];
for( int j = off; j < stop; j++ ) {
b[ j ] = 0.0f;
}
}
}
/** Clears two dimensional array. */
public static void clear(double[][] a, int off, int length) {
final int stop = off + length;
double[] b;
for (int i = 0; i < a.length; i++) {
b = a[i];
for (int j = off; j < stop; j++) {
b[j] = 0.0;
}
}
}
/** Clears one dimensioal array. */
public static void clear(double[] a, int off, int length) {
final int stop = off + length;
for (int j = off; j < stop; j++) {
a[j] = 0.0;
}
}
/**
* Eindimensionales Array loeschen
*/
public static void clear( float[] a, int off, int length )
{
final int stop = off + length;
for( int j = off; j < stop; j++ ) {
a[ j ] = 0.0f;
}
}
/**
* Eindimensionales Array umkehren
*/
public static void reverse( float[] a, int off, int length )
{
float tmp;
for( int i = off, j = off + length - 1; i < j; i++, j-- ) {
tmp = a[ i ];
a[ i ] = a[ j ];
a[ j ] = tmp;
}
}
/**
* Zweidimensionales Array umkehren
*/
public static void reverse( float[][] a, int off, int length )
{
final int last = off + length - 1;
float tmp;
float[] b;
for( int k = 0; k < a.length; k++ ) {
b = a[ k ];
for( int i = off, j = last; i < j; i++, j-- ) {
tmp = b[ i ];
b[ i ] = b[ j ];
b[ j ] = tmp;
}
}
}
public static void reverse( double[][] a, int off, int length )
{
final int last = off + length - 1;
double tmp;
double[] b;
for( int k = 0; k < a.length; k++ ) {
b = a[ k ];
for( int i = off, j = last; i < j; i++, j-- ) {
tmp = b[ i ];
b[ i ] = b[ j ];
b[ j ] = tmp;
}
}
}
public static float sum( float[] a, int off, int length )
{
double d = 0.0;
final int stop = off + length;
while( off < stop ) d += a[ off++ ];
return (float) d;
}
public static float meanSquare( float[] a, int off, int length )
{
double d = 0.0, d1;
final int stop = off + length;
while( off < stop ) {
d1 = a[ off++ ];
d += d1 * d1;
}
return (float) (d / length);
}
public static float mean( float[] a, int off, int length )
{
return sum( a, off, length ) / length;
}
public static float maxAbs( float[] a, int off, int length )
{
final int stop = off + length;
float f1 = 0f, f2;
while( off < stop ) {
f2 = Math.abs( a[ off++ ]);
if( f2 > f1 ) f1 = f2;
}
return f1;
}
public static float maxAbs( float[][] a, int off, int length )
{
final int stop = off + length;
float f1 = 0f, f2;
float[] b;
for( int i = 0; i < a.length; i++ ) {
b = a[ i ];
for( int j = off; j < stop; j++ ) {
f2 = Math.abs( b[ j ]);
if( f2 > f1 ) f1 = f2;
}
}
return f1;
}
public static float removeDC( float[] a, int off, int length )
{
if( length == 0 ) return 0f;
final float sum = sum( a, off, length );
final float dc = sum / length;
if( dc != 0f ) {
add( a, off, length, -dc );
}
return dc;
}
public static void copy( float[][] src, int srcOff, float[][] dest, int destOff, int length )
{
for( int i = 0; i < src.length; i++ ) {
System.arraycopy( src[ i ], srcOff, dest[ i ], destOff, length );
}
}
public static int nextPowerOfTwo( int x )
{
int y = 1;
while( y < x ) y <<= 1;
return y;
}
/**
* Creates a list from an iterator
*
* @param iter an iterator whose contents should be returned as an array
* @return the iterator elements as an array
*/
public static List iterToList( Iterator iter )
{
final List foo = new ArrayList();
while( iter.hasNext() ) {
foo.add( iter.next() );
}
return foo;
}
/**
* Creates an array from an iterator
*
* @param iter an iterator whose contents should be returned as an array
* @return the iterator elements as an array
*/
public static Object[] iterToArray( Iterator iter )
{
return iterToList( iter ).toArray();
}
/**
* Erzeugt Array aus einer Enumeration
*/
// public static Object[] enumToArray( Enumeration enum )
// {
// Vector foo = new Vector();
// while( enum.hasMoreElements() ) {
// foo.addElement( enum.nextElement() );
// }
// Object[] array = new Object[ foo.size() ];
// for( int i = 0; i < foo.size(); i++ ) {
// array[ i ] = foo.elementAt( i );
// }
// return array;
// }
public static double linexp( double x, double inLo, double inHi, double outLo, double outHi )
{
return Math.pow( outHi / outLo, (x - inLo) / (inHi - inLo) ) * outLo;
}
public static double explin( double x, double inLo, double inHi, double outLo, double outHi )
{
return Math.log( x / inLo ) / Math.log( inHi / inLo ) * (outHi - outLo) + outLo;
}
/*
* Sorts an array data[0...len-1] into ascending order using Quicksort, while making the corresponding
* rearrangement of the array dataIdx[0...len-1].
*/
public static void quickSortFloat( float[] data, int[] dataIdx, int len )
{
int scanGt, scanLt, iterLen = len, k, l = 1;
int[] stack = new int[ 65 ]; // >= 2 * ld N
int stackIdx = 0;
float dataElem, tempF;
int dataIdxElem, tempI;
int kDec, lDec = 0, iterLenDec = iterLen - 1;
while( true ) { // Insertion sort when subarray small enough.
if( iterLen - l < 7 ) { // M = 7
for( scanGt = l; scanGt < iterLen; scanGt++ ) {
dataElem = data[scanGt];
dataIdxElem = dataIdx[scanGt];
for( scanLt = scanGt-1; scanLt+1 >= l; scanLt-- ) {
if( data[scanLt] <= dataElem ) break;
data[scanLt+1] = data[scanLt];
dataIdx[scanLt+1] = dataIdx[scanLt];
}
data[scanLt+1] = dataElem;
dataIdx[scanLt+1] = dataIdxElem;
}
if( stackIdx == 0 ) {
// free_lvector(stack,1,NSTACK);
return;
}
iterLen = stack[stackIdx]; // Pop stack and begin a new round of partitioning.
iterLenDec = iterLen-1;
l = stack[stackIdx-1];
lDec = l-1;
stackIdx -= 2;
} else {
// Choose median of left, center and right elements
// as partitioning element dataElem. Also
// rearrange so that dataElem[l] <= dataElem[l+1] <= dataElem[iterLen].
k = (l+iterLen) >> 1;
kDec = k-1;
tempF = data[kDec]; // SWAP(data[k],data[l+1])
data[kDec] = data[l];
data[l] = tempF;
tempI = dataIdx[kDec]; // SWAP(dataIdx[k],dataIdx[l+1])
dataIdx[kDec] = dataIdx[l];
dataIdx[l] = tempI;
if( data[lDec] > data[iterLenDec] ) {
tempF = data[lDec]; // SWAP(data[l],data[iterLen])
data[lDec] = data[iterLenDec];
data[iterLenDec] = tempF;
tempI = dataIdx[lDec]; // SWAP(dataIdx[l],dataIdx[iterLen])
dataIdx[lDec] = dataIdx[iterLenDec];
dataIdx[iterLenDec] = tempI;
}
if( data[l] > data[iterLenDec] ) {
tempF = data[l]; // SWAP(data[l+1],data[iterLen])
data[l] = data[iterLenDec];
data[iterLenDec] = tempF;
tempI = dataIdx[l]; // SWAP(dataIdx[l+1],dataIdx[iterLen])
dataIdx[l] = dataIdx[iterLenDec];
dataIdx[iterLenDec] = tempI;
}
if( data[lDec] > data[l] ) {
tempF = data[lDec]; // SWAP(data[l],data[l+1])
data[lDec] = data[l];
data[l] = tempF;
tempI = dataIdx[lDec]; // SWAP(dataIdx[l],dataIdx[l+1])
dataIdx[lDec] = dataIdx[l];
dataIdx[l] = tempI;
}
scanGt = l; // Initialize pointers for partitioning.
scanLt = iterLenDec;
dataElem = data[l]; // Partitioning element.
dataIdxElem = dataIdx[l];
while( true ) { // Beginning of innermost loop.
do scanGt++; while( data[scanGt] < dataElem ); // Scan up to find element > dataElem.
do scanLt--; while( data[scanLt] > dataElem ); // Scan down to find element < dataElem.
if( scanLt < scanGt ) break; // Pointers crossed. Partitioning complete.
tempF = data[scanGt]; // SWAP(data[scanGt],data[scanLt])
data[scanGt] = data[scanLt];
data[scanLt] = tempF;
tempI = dataIdx[scanGt]; // SWAP(dataIdx[scanGt],dataIdx[scanLt])
dataIdx[scanGt] = dataIdx[scanLt];
dataIdx[scanLt] = tempI;
} // End of innermost loop.
data[l] = data[scanLt]; // Insert partitioning element in both arrays.
data[scanLt] = dataElem;
dataIdx[l] = dataIdx[scanLt];
dataIdx[scanLt] = dataIdxElem;
stackIdx += 2;
scanGt++;
// Push pointers to larger subarray on stack, process smaller subarray immediately.
// if( stackIdx > NSTACK ) nrerror("NSTACK too small in sort2.");
if( iterLen-scanGt >= scanLt-l ) {
stack[stackIdx] = iterLen;
stack[stackIdx-1] = scanGt;
iterLen = scanLt;
iterLenDec = iterLen-1;
} else {
stack[stackIdx] = scanLt;
stack[stackIdx-1] = l;
l = scanGt;
lDec = l-1;
}
}
}
}
// /**
// * Lazily sorts the data. Throws a
// * <code>RuntimeException</code> if any object
// * in the array is not <code>Comparable</code>.
// *
// * @param data array of objects implementing the
// * <code>Comparable</code> interface
// * @param ascending <code>true</code> to sort in ascending order,
// * <code>false</code> to sort in descending order
// *
// * @see java.lang.Comparable
// */
// public static void sort( Object[] data, boolean ascending )
// {
// Object a, b;
// final int mult = ascending ? 1 : -1;
// int i, restart = 0;
//
// do {
// for( i = restart, restart = data.length; i < data.length - 1; i++ ) {
// a = data[ i ];
// b = data[ i + 1 ];
// if( ((Comparable) a).compareTo( b ) * mult > 0 ) {
// data[ i+1 ] = a;
// data[ i ] = b;
// restart = Math.min( restart, Math.max( 0, i - 1 ));
// }
// }
// } while( restart < data.length );
// }
/*
* Sorts an array data[0...len-1] into ascending order using Quicksort
* rearrangement of the array dataIdx[0...len-1].
*/
public static void quickSortInt( int[] data, int[] dataIdx, int len )
{
int scanGt, scanLt, iterLen = len, k, l = 1;
int[] stack = new int[ 65 ]; // >= 2 * ld N
int stackIdx = 0;
int dataElem, dataIdxElem, temp;
int kDec, lDec = 0, iterLenDec = iterLen - 1;
while( true ) { // Insertion sort when subarray small enough.
if( iterLen - l < 7 ) { // M = 7
for( scanGt = l; scanGt < iterLen; scanGt++ ) {
dataElem = data[scanGt];
dataIdxElem = dataIdx[scanGt];
for( scanLt = scanGt-1; scanLt+1 >= l; scanLt-- ) {
if( data[scanLt] <= dataElem ) break;
data[scanLt+1] = data[scanLt];
dataIdx[scanLt+1] = dataIdx[scanLt];
}
data[scanLt+1] = dataElem;
dataIdx[scanLt+1] = dataIdxElem;
}
if( stackIdx == 0 ) {
// free_lvector(stack,1,NSTACK);
return;
}
iterLen = stack[stackIdx]; // Pop stack and begin a new round of partitioning.
iterLenDec = iterLen-1;
l = stack[stackIdx-1];
lDec = l-1;
stackIdx -= 2;
} else {
// Choose median of left, center and right elements
// as partitioning element dataElem. Also
// rearrange so that dataElem[l] <= dataElem[l+1] <= dataElem[iterLen].
k = (l+iterLen) >> 1;
kDec = k-1;
temp = data[kDec]; // SWAP(data[k],data[l+1])
data[kDec] = data[l];
data[l] = temp;
temp = dataIdx[kDec]; // SWAP(dataIdx[k],dataIdx[l+1])
dataIdx[kDec] = dataIdx[l];
dataIdx[l] = temp;
if( data[lDec] > data[iterLenDec] ) {
temp = data[lDec]; // SWAP(data[l],data[iterLen])
data[lDec] = data[iterLenDec];
data[iterLenDec] = temp;
temp = dataIdx[lDec]; // SWAP(dataIdx[l],dataIdx[iterLen])
dataIdx[lDec] = dataIdx[iterLenDec];
dataIdx[iterLenDec] = temp;
}
if( data[l] > data[iterLenDec] ) {
temp = data[l]; // SWAP(data[l+1],data[iterLen])
data[l] = data[iterLenDec];
data[iterLenDec] = temp;
temp = dataIdx[l]; // SWAP(dataIdx[l+1],dataIdx[iterLen])
dataIdx[l] = dataIdx[iterLenDec];
dataIdx[iterLenDec] = temp;
}
if( data[lDec] > data[l] ) {
temp = data[lDec]; // SWAP(data[l],data[l+1])
data[lDec] = data[l];
data[l] = temp;
temp = dataIdx[lDec]; // SWAP(dataIdx[l],dataIdx[l+1])
dataIdx[lDec] = dataIdx[l];
dataIdx[l] = temp;
}
scanGt = l; // Initialize pointers for partitioning.
scanLt = iterLenDec;
dataElem = data[l]; // Partitioning element.
dataIdxElem = dataIdx[l];
while( true ) { // Beginning of innermost loop.
do scanGt++; while( data[scanGt] < dataElem ); // Scan up to find element > dataElem.
do scanLt--; while( data[scanLt] > dataElem ); // Scan down to find element < dataElem.
if( scanLt < scanGt ) break; // Pointers crossed. Partitioning complete.
temp = data[scanGt]; // SWAP(data[scanGt],data[scanLt])
data[scanGt] = data[scanLt];
data[scanLt] = temp;
temp = dataIdx[scanGt]; // SWAP(dataIdx[scanGt],dataIdx[scanLt])
dataIdx[scanGt] = dataIdx[scanLt];
dataIdx[scanLt] = temp;
} // End of innermost loop.
data[l] = data[scanLt]; // Insert partitioning element in both arrays.
data[scanLt] = dataElem;
dataIdx[l] = dataIdx[scanLt];
dataIdx[scanLt] = dataIdxElem;
stackIdx += 2;
scanGt++;
// Push pointers to larger subarray on stack, process smaller subarray immediately.
// if( stackIdx > NSTACK ) nrerror("NSTACK too small in sort2.");
if( iterLen-scanGt >= scanLt-l ) {
stack[stackIdx] = iterLen;
stack[stackIdx-1] = scanGt;
iterLen = scanLt;
iterLenDec = iterLen-1;
} else {
stack[stackIdx] = scanLt;
stack[stackIdx-1] = l;
l = scanGt;
lDec = l-1;
}
}
}
}
/*
* The below sort algorithm is a modification of the Arrays.sort
* method of OpenJDK 7 which is (C)opyright 1997-2007 by Sun
* Microsystems, Inc., and covered by the GNU General Public
* License v2.
*
* The modification made is the additional corr argument which
* is an arbitrary array that gets sorted along with the x vector.
*/
/*
* Sorts the specified sub-array of doubles into ascending order.
*/
public static void sort( double x[], Object[] corr, int off, int len )
{
// Insertion sort on smallest arrays
if( len < 7 ) {
for( int i = off; i < len + off; i++ ) {
for( int j = i; (j > off) && (x[ j - 1 ] > x[ j ]); j-- ) {
swap( x, corr, j, j - 1 );
}
}
return;
}
// Choose a partition element, v
int m = off + (len >> 1); // Small arrays, middle element
if( len > 7 ) {
int l = off;
int n = off + len - 1;
if( len > 40 ) { // Big arrays, pseudomedian of 9
final int s = len / 8;
l = med3( x, l, l + s, l + 2 * s );
m = med3( x, m - s, m, m + s );
n = med3( x, n - 2 * s, n - s, n );
}
m = med3( x, l, m, n ); // Mid-size, med of 3
}
final double v = x[ m ];
// Establish Invariant: v* (<v)* (>v)* v*
int a = off, b = a, c = off + len - 1, d = c;
while( true ) {
while( (b <= c) && (x[ b ] <= v) ) {
if( x[ b ] == v ) swap( x, corr, a++, b );
b++;
}
while( c >= b && x[ c ] >= v ) {
if( x[ c ] == v ) swap( x, corr, c, d-- );
c--;
}
if( b > c ) break;
swap( x, corr, b++, c-- );
}
// Swap partition elements back to middle
int s, n = off + len;
s = Math.min( a - off, b - a );
vecswap( x, corr, off, b - s, s );
s = Math.min( d - c, n - d - 1 );
vecswap( x, corr, b, n - s, s );
// Recursively sort non-partition-elements
if( (s = b - a) > 1 ) sort( x, corr, off, s );
if( (s = d - c) > 1 ) sort( x, corr, n - s, s );
}
/*
* Swaps x[a] with x[b].
*/
private static void swap( double x[], Object[] corr, int a, int b )
{
final double tmpX = x[ a ];
x[ a ] = x[ b ];
x[ b ] = tmpX;
final Object tmpCorr = corr[ a ];
corr[ a ] = corr[ b ];
corr[ b ] = tmpCorr;
}
/*
* Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
*/
private static void vecswap( double x[], Object[] corr, int a, int b, int n )
{
for( int i = 0; i < n; i++, a++, b++ ) {
swap( x, corr, a, b );
}
}
/**
* Returns the index of the median of the three indexed doubles.
*/
private static int med3( double x[], int a, int b, int c )
{
return(x[ a ] < x[ b ] ? (x[ b ] < x[ c ] ? b : x[ a ] < x[ c ] ? c : a) : (x[ b ] > x[ c ] ? b
: x[ a ] > x[ c ] ? c : a));
}
}
// class Util