/*
 * @(#)Conversions.java    2.3  23 June 2003
 *
 * Copyright 2004
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.util;

/**
 * <P>Class <CODE>Conversions</CODE> contains type conversion utility
 * functions suitable for processing byte sequences and byte arrays
 * and for conversion of integral values (short, int, or long) to
 * floating values (float or double) that are between -1 and +1.</P>
 *
 * <P>Class <CODE>Conversions</CODE> cannot be instantiated.</P>
 *
 * @author Richard Rasala
 * @version 2.3
 * @since   1.0
 */
public class Conversions {
    
    /** Private constructor to prevent instantiation. */
    private Conversions() {}
    
    
    /////////////////
    // short tools //
    /////////////////
    
    /**
     * <P>Returns the short constructed from the byte array
     * assuming that the byte order is low-to-high.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or has
     * length 0, return 0.</P>
     *
     * <P>If the byte array does not have enough items then
     * assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: 0 to 1.</P>
     *
     * @param b the byte array
     * @return the short constructed from the byte array
     * @see #bytesToShortLoHi(byte[], int)
     * @see #bytesToShortLoHi(byte, byte)
     * @see #bytesToShortHiLo(byte[])
     * @see #bytesToShortHiLo(byte[], int)
     * @see #bytesToShortHiLo(byte, byte)
     */
    public static short bytesToShortLoHi(byte[] b) {
        return bytesToShortLoHi(b, 0);
    }

    
    /**
     * <P>Returns the short constructed from the byte array
     * starting at the given start index
     * and assuming that the byte order is low-to-high.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or start
     * is not a valid index into the byte array, return 0.</P>
     *
     * <P>If the byte array does not have enough items from
     * start onward then assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: start to (start + 1).</P>
     *
     * @param b the byte array
     * @param start the start index
     * @return the short constructed from the byte array
     * @see #bytesToShortLoHi(byte[])
     * @see #bytesToShortLoHi(byte, byte)
     * @see #bytesToShortHiLo(byte[])
     * @see #bytesToShortHiLo(byte[], int)
     * @see #bytesToShortHiLo(byte, byte)
     */
    public static short bytesToShortLoHi(byte[] b, int start) {
        final int size = 2;
        
        if (b == null)
            return 0;
        
        int length = b.length;
        
        if ((start < 0) || (start >= length))
            return 0;
        
        int limit = Math.min(length - start, size);

        short x = 0;
        int mask = 0xFF;
        
        for (int i = 0; i < limit; i++) {
            int y = b[start + i];
            y = y << (8 * i);
            y = y & mask;
            
            x = (short) ((int)x | y);
            mask = mask << 8;
        }
        
        return x;
    }

    
    /**
     * <P>Returns the short constructed from the pair of bytes assuming
     * <CODE>b0</CODE> is the low byte
     * and
     * <CODE>b1</CODE> is the high byte.</P>
     *
     * @param b0 the low byte
     * @param b1 the high byte
     * @return the short constructed from b0 and b1
     * @see #bytesToShortLoHi(byte[])
     * @see #bytesToShortLoHi(byte[], int)
     * @see #bytesToShortHiLo(byte[])
     * @see #bytesToShortHiLo(byte[], int)
     * @see #bytesToShortHiLo(byte, byte)
     */
    public static short bytesToShortLoHi(byte b0, byte b1) {
        return bytesToShortLoHi
            (new byte[] { b0, b1 }, 0);
    }

    
    /**
     * <P>Returns the short constructed from the byte array
     * assuming that the byte order is high-to-low.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or has
     * length 0, return 0.</P>
     *
     * <P>If the byte array does not have enough items then
     * assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: 0 to 1.</P>
     *
     * @param b the byte array
     * @return the short constructed from the byte array
     * @see #bytesToShortLoHi(byte[])
     * @see #bytesToShortLoHi(byte[], int)
     * @see #bytesToShortLoHi(byte, byte)
     * @see #bytesToShortHiLo(byte[], int)
     * @see #bytesToShortHiLo(byte, byte)
     */
    public static short bytesToShortHiLo(byte[] b) {
        return bytesToShortHiLo(b, 0);
    }

    
    /**
     * <P>Returns the short constructed from the byte array
     * starting at the given start index
     * and assuming that the byte order is high-to-low.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or start
     * is not a valid index into the byte array, return 0.</P>
     *
     * <P>If the byte array does not have enough items from
     * start onward then assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: start to (start + 1).</P>
     *
     * @param b the byte array
     * @param start the start index
     * @return the short constructed from the byte array
     * @see #bytesToShortLoHi(byte[])
     * @see #bytesToShortLoHi(byte[], int)
     * @see #bytesToShortLoHi(byte, byte)
     * @see #bytesToShortHiLo(byte[])
     * @see #bytesToShortHiLo(byte, byte)
     */
    public static short bytesToShortHiLo(byte[] b, int start) {
        final int size = 2;
        final int last = size - 1;
        
        if (b == null)
            return 0;
        
        int length = b.length;
        
        if ((start < 0) || (start >= length))
            return 0;
        
        int limit = Math.min(length - start, size);

        byte[] c = new byte[size];
        
        for (int i = 0; i < limit; i++)
            c[last - i] = b[start + i];
        
        return bytesToShortLoHi(c, 0);
    }
    
    
    /**
     * <P>Returns the short constructed from the pair of bytes assuming
     * <CODE>b0</CODE> is the high byte
     * and
     * <CODE>b1</CODE> is the low byte.</P>
     *
     * @param b0 the high byte
     * @param b1 the low byte
     * @return the short constructed from b0 and b1
     * @see #bytesToShortLoHi(byte[])
     * @see #bytesToShortLoHi(byte[], int)
     * @see #bytesToShortLoHi(byte, byte)
     * @see #bytesToShortHiLo(byte[])
     * @see #bytesToShortHiLo(byte[], int)
     */
    public static short bytesToShortHiLo(byte b0, byte b1) {
        return bytesToShortLoHi
            (new byte[] { b1, b0 }, 0);
    }

    
    /**
     * <P>Returns an array of bytes of size 2
     * with the 2 bytes of the given short in low-to-high order.</P>
     *
     * @param s the short that defines the bytes
     * @return the associated byte array
     * @see #shortToBytesHiLo(short)
     */
    public static byte[] shortToBytesLoHi(short s) {
        final int size = 2;
        
        byte[] data = new byte[size];
        int t = s;
        
        for (int i = 0; i < size; i++) {
            data[i] = (byte) t;
            t = t >> 8;
        }
        
        return data;
    }
    
    
    /**
     * <P>Returns an array of bytes of size 2
     * with the 2 bytes of the given short in high-to-low order.</P>
     *
     * @param s the short that defines the bytes
     * @return the associated byte array
     * @see #shortToBytesLoHi(short)
     */
    public static byte[] shortToBytesHiLo(short s) {
        final int size = 2;
        final int last = size - 1;
        
        byte[] data = new byte[size];
        int t = s;
        
        for (int i = 0; i < size; i++) {
            data[last - i] = (byte) t;
            t = t >> 8;
        }
        
        return data;
    }
    
    
    ///////////////
    // int tools //
    ///////////////
    
    /**
     * <P>Returns the int constructed from the byte array
     * assuming that the byte order is low-to-high.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or has
     * length 0, return 0.</P>
     *
     * <P>If the byte array does not have enough items then
     * assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: 0 to 3.</P>
     *
     * @param b the byte array
     * @return the int constructed from the byte array
     * @see #bytesToIntLoHi(byte[], int)
     * @see #bytesToIntLoHi(byte, byte, byte, byte)
     * @see #bytesToIntHiLo(byte[])
     * @see #bytesToIntHiLo(byte[], int)
     * @see #bytesToIntHiLo(byte, byte, byte, byte)
     */
    public static int bytesToIntLoHi(byte[] b) {
        return bytesToIntLoHi(b, 0);
    }

    
    /**
     * <P>Returns the int constructed from the byte array
     * starting at the given start index
     * and assuming that the byte order is low-to-high.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or start
     * is not a valid index into the byte array, return 0.</P>
     *
     * <P>If the byte array does not have enough items from
     * start onward then assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: start to (start + 3).</P>
     *
     * @param b the byte array
     * @param start the start index
     * @return the int constructed from the byte array
     * @see #bytesToIntLoHi(byte[])
     * @see #bytesToIntLoHi(byte, byte, byte, byte)
     * @see #bytesToIntHiLo(byte[])
     * @see #bytesToIntHiLo(byte[], int)
     * @see #bytesToIntHiLo(byte, byte, byte, byte)
     */
    public static int bytesToIntLoHi(byte[] b, int start) {
        final int size = 4;
        
        if (b == null)
            return 0;
        
        int length = b.length;
        
        if ((start < 0) || (start >= length))
            return 0;
        
        int limit = Math.min(length - start, size);

        int x = 0;
        int mask = 0xFF;
        
        for (int i = 0; i < limit; i++) {
            int y = b[start + i];
            y = y << (8 * i);
            y = y & mask;
            
            x = x | y;
            mask = mask << 8;
        }
        
        return x;
    }

    
    /**
     * <P>Returns the int constructed from the four given bytes assuming
     * the byte order is low-to-high.</P>
     *
     * @param b0 the lowest byte
     * @param b1 the next byte
     * @param b2 the next byte
     * @param b3 the next byte
     * @return the int constructed from the four bytes
     * @see #bytesToIntLoHi(byte[])
     * @see #bytesToIntLoHi(byte[], int)
     * @see #bytesToIntHiLo(byte[])
     * @see #bytesToIntHiLo(byte[], int)
     * @see #bytesToIntHiLo(byte, byte, byte, byte)
     */
    public static int bytesToIntLoHi(byte b0, byte b1, byte b2, byte b3) {
        return bytesToIntLoHi
            (new byte[] { b0, b1, b2, b3 }, 0);
    }
    
    
    /**
     * <P>Returns the int constructed from the byte array
     * assuming that the byte order is high-to-low.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or has
     * length 0, return 0.</P>
     *
     * <P>If the byte array does not have enough items then
     * assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: 0 to 3.</P>
     *
     * @param b the byte array
     * @return the int constructed from the byte array
     * @see #bytesToIntLoHi(byte[])
     * @see #bytesToIntLoHi(byte[], int)
     * @see #bytesToIntLoHi(byte, byte, byte, byte)
     * @see #bytesToIntHiLo(byte[], int)
     * @see #bytesToIntHiLo(byte, byte, byte, byte)
     */
    public static int bytesToIntHiLo(byte[] b) {
        return bytesToIntHiLo(b, 0);
    }

    
    /**
     * <P>Returns the int constructed from the byte array
     * starting at the given start index
     * and assuming that the byte order is high-to-low.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or start
     * is not a valid index into the byte array, return 0.</P>
     *
     * <P>If the byte array does not have enough items from
     * start onward then assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: start to (start + 3).</P>
     *
     * @param b the byte array
     * @param start the start index
     * @return the int constructed from the byte array
     * @see #bytesToIntLoHi(byte[])
     * @see #bytesToIntLoHi(byte[], int)
     * @see #bytesToIntLoHi(byte, byte, byte, byte)
     * @see #bytesToIntHiLo(byte[])
     * @see #bytesToIntHiLo(byte, byte, byte, byte)
     */
    public static int bytesToIntHiLo(byte[] b, int start) {
        final int size = 4;
        final int last = size - 1;
        
        if (b == null)
            return 0;
        
        int length = b.length;
        
        if ((start < 0) || (start >= length))
            return 0;
        
        int limit = Math.min(length - start, size);

        byte[] c = new byte[size];
        
        for (int i = 0; i < limit; i++)
            c[last - i] = b[start + i];
        
        return bytesToIntLoHi(c, 0);
    }
    
    
    /**
     * <P>Returns the int constructed from the four given bytes assuming
     * the byte order is high-to-low.</P>
     *
     * @param b0 the highest byte
     * @param b1 the next byte
     * @param b2 the next byte
     * @param b3 the next byte
     * @return the int constructed from the four bytes
     * @see #bytesToIntLoHi(byte[])
     * @see #bytesToIntLoHi(byte[], int)
     * @see #bytesToIntLoHi(byte, byte, byte, byte)
     * @see #bytesToIntHiLo(byte[])
     * @see #bytesToIntHiLo(byte[], int)
     */
    public static int bytesToIntHiLo(byte b0, byte b1, byte b2, byte b3) {
        return bytesToIntLoHi
            (new byte[] { b3, b2, b1, b0 }, 0);
    }

    
    /**
     * <P>Returns an array of bytes of size 4
     * with the 4 bytes of the given int in low-to-high order.</P>
     *
     * @param s the int that defines the bytes
     * @return the associated byte array
     * @see #intToBytesHiLo(int)
     */
    public static byte[] intToBytesLoHi(int s) {
        final int size = 4;
        
        byte[] data = new byte[size];
        
        for (int i = 0; i < size; i++) {
            data[i] = (byte) s;
            s = s >> 8;
        }
        
        return data;
    }
    
    
    /**
     * <P>Returns an array of bytes of size 4
     * with the 4 bytes of the given int in high-to-low order.</P>
     *
     * @param s the int that defines the bytes
     * @return the associated byte array
     * @see #intToBytesLoHi(int)
     */
    public static byte[] intToBytesHiLo(int s) {
        final int size = 4;
        final int last = size - 1;
        
        byte[] data = new byte[size];
        
        for (int i = 0; i < size; i++) {
            data[last - i] = (byte) s;
            s = s >> 8;
        }
        
        return data;
    }
    
    
    ////////////////
    // long tools //
    ////////////////
    
    /**
     * <P>Returns the long constructed from the byte array
     * assuming that the byte order is low-to-high.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or has
     * length 0, return 0.</P>
     *
     * <P>If the byte array does not have enough items then
     * assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: 0 to 7.</P>
     *
     * @param b the byte array
     * @return the long constructed from the byte array
     * @see #bytesToLongLoHi(byte[], int)
     * @see #bytesToLongLoHi(byte, byte, byte, byte, byte, byte, byte, byte)
     * @see #bytesToLongHiLo(byte[])
     * @see #bytesToLongHiLo(byte[], int)
     * @see #bytesToLongHiLo(byte, byte, byte, byte, byte, byte, byte, byte)
     */
    public static long bytesToLongLoHi(byte[] b) {
        return bytesToLongLoHi(b, 0);
    }

    
    /**
     * <P>Returns the long constructed from the byte array
     * starting at the given start index
     * and assuming that the byte order is low-to-high.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or start
     * is not a valid index into the byte array, return 0.</P>
     *
     * <P>If the byte array does not have enough items from
     * start onward then assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: start to (start + 7).</P>
     *
     * @param b the byte array
     * @param start the start index
     * @return the long constructed from the byte array
     * @see #bytesToLongLoHi(byte[])
     * @see #bytesToLongLoHi(byte, byte, byte, byte, byte, byte, byte, byte)
     * @see #bytesToLongHiLo(byte[])
     * @see #bytesToLongHiLo(byte[], int)
     * @see #bytesToLongHiLo(byte, byte, byte, byte, byte, byte, byte, byte)
     */
    public static long bytesToLongLoHi(byte[] b, int start) {
        final int size = 8;
        
        if (b == null)
            return 0;
        
        int length = b.length;
        
        if ((start < 0) || (start >= length))
            return 0;
        
        int limit = Math.min(length - start, size);

        long x = 0;
        long mask = 0xFF;
        
        for (int i = 0; i < limit; i++) {
            long y = b[start + i];
            y = y << (8 * i);
            y = y & mask;
            
            x = x | y;
            mask = mask << 8;
        }
        
        return x;
    }

    
    /**
     * <P>Returns the long constructed from the eight given bytes assuming
     * the byte order is low-to-high.</P>
     *
     * @param b0 the lowest byte
     * @param b1 the next byte
     * @param b2 the next byte
     * @param b3 the next byte
     * @param b4 the next byte
     * @param b5 the next byte
     * @param b6 the next byte
     * @param b7 the next byte
     * @return the long constructed from the eight bytes
     * @see #bytesToLongLoHi(byte[])
     * @see #bytesToLongLoHi(byte[], int)
     * @see #bytesToLongHiLo(byte[])
     * @see #bytesToLongHiLo(byte[], int)
     * @see #bytesToLongHiLo(byte, byte, byte, byte, byte, byte, byte, byte)
     */
    public static long bytesToLongLoHi
        (byte b0, byte b1, byte b2, byte b3,
         byte b4, byte b5, byte b6, byte b7)
    {
        return bytesToLongLoHi
            (new byte[] { b0, b1, b2, b3, b4, b5, b6, b7 }, 0);
    }
    
    
    /**
     * <P>Returns the long constructed from the byte array
     * assuming that the byte order is high-to-low.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or has
     * length 0, return 0.</P>
     *
     * <P>If the byte array does not have enough items then
     * assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: 0 to 7.</P>
     *
     * @param b the byte array
     * @return the long constructed from the byte array
     * @see #bytesToLongLoHi(byte[])
     * @see #bytesToLongLoHi(byte[], int)
     * @see #bytesToLongLoHi(byte, byte, byte, byte, byte, byte, byte, byte)
     * @see #bytesToLongHiLo(byte[], int)
     * @see #bytesToLongHiLo(byte, byte, byte, byte, byte, byte, byte, byte)
     */
    public static long bytesToLongHiLo(byte[] b) {
        return bytesToLongHiLo(b, 0);
    }

    
    /**
     * <P>Returns the long constructed from the byte array
     * starting at the given start index
     * and assuming that the byte order is high-to-low.</P>
     *
     * <P>If the byte array is <CODE>null</CODE> or start
     * is not a valid index into the byte array, return 0.</P>
     *
     * <P>If the byte array does not have enough items from
     * start onward then assume the missing items are 0.</P>
     *
     * <P>Ignore items in the byte array that are not in the
     * range: start to (start + 7).</P>
     *
     * @param b the byte array
     * @param start the start index
     * @return the long constructed from the byte array
     * @see #bytesToLongLoHi(byte[])
     * @see #bytesToLongLoHi(byte[], int)
     * @see #bytesToLongLoHi(byte, byte, byte, byte, byte, byte, byte, byte)
     * @see #bytesToLongHiLo(byte[])
     * @see #bytesToLongHiLo(byte, byte, byte, byte, byte, byte, byte, byte)
     */
    public static long bytesToLongHiLo(byte[] b, int start) {
        final int size = 8;
        final int last = size - 1;
        
        if (b == null)
            return 0;
        
        int length = b.length;
        
        if ((start < 0) || (start >= length))
            return 0;
        
        int limit = Math.min(length - start, size);

        byte[] c = new byte[size];
        
        for (int i = 0; i < limit; i++)
            c[last - i] = b[start + i];
        
        return bytesToLongLoHi(c, 0);
    }
    
    
    /**
     * <P>Returns the long constructed from the eight given bytes assuming
     * the byte order is high-to-low.</P>
     *
     * @param b0 the highest byte
     * @param b1 the next byte
     * @param b2 the next byte
     * @param b3 the next byte
     * @param b4 the next byte
     * @param b5 the next byte
     * @param b6 the next byte
     * @param b7 the next byte
     * @return the long constructed from the eight bytes
     * @see #bytesToLongLoHi(byte[])
     * @see #bytesToLongLoHi(byte[], int)
     * @see #bytesToLongLoHi(byte, byte, byte, byte, byte, byte, byte, byte)
     * @see #bytesToLongHiLo(byte[])
     * @see #bytesToLongHiLo(byte[], int)
     */
    public static long bytesToLongHiLo
        (byte b0, byte b1, byte b2, byte b3,
         byte b4, byte b5, byte b6, byte b7)
    {
        return bytesToLongLoHi
            (new byte[] { b7, b6, b5, b4, b3, b2, b1, b0 }, 0);
    }

    
    /**
     * <P>Returns an array of bytes of size 8
     * with the 8 bytes of the given long in low-to-high order.</P>
     *
     * @param s the long that defines the bytes
     * @return the associated byte array
     * @see #longToBytesHiLo(long)
     */
    public static byte[] longToBytesLoHi(long s) {
        final int size = 8;
        
        byte[] data = new byte[size];
        
        for (int i = 0; i < size; i++) {
            data[i] = (byte) s;
            s = s >> 8;
        }
        
        return data;
    }
    
    
    /**
     * <P>Returns an array of bytes of size 8
     * with the 8 bytes of the given long in high-to-low order.</P>
     *
     * @param s the long that defines the bytes
     * @return the associated byte array
     * @see #longToBytesLoHi(long)
     */
    public static byte[] longToBytesHiLo(long s) {
        final int size = 8;
        final int last = size - 1;
        
        byte[] data = new byte[size];
        
        for (int i = 0; i < size; i++) {
            data[last - i] = (byte) s;
            s = s >> 8;
        }
        
        return data;
    }
    
    
    /////////////////
    // float tools //
    /////////////////
    
    /**
     * <P>Returns the float between -1 and +1 calculated by dividing
     * the given short by <CODE>Short.MAX_VALUE</CODE>.</P>
     *
     * <P>The short <CODE>Short.MIN_VALUE</CODE> is treated as a special
     * case.  For this value, the method returns -1.</P>
     *
     * @param s the short to convert to a float between -1 and +1
     * @return the resulting float
     */
   public static float shortToFloat(short s) {
        if (s == Short.MIN_VALUE)
            return -1.0f;

        return ((float) s) / ((float) Short.MAX_VALUE);
    }
    
    
    /**
     * <P>Returns the float between -1 and +1 calculated by dividing
     * the given int by <CODE>Integer.MAX_VALUE</CODE>.</P>
     *
     * <P>The int <CODE>Integer.MIN_VALUE</CODE> is treated as a special
     * case.  For this value, the method returns -1.</P>
     *
     * <P>The method intends to map an int to a float between -1 and +1.
     * Its value is quite different from that of the following method in
     * class <CODE>Float</CODE>:</P>
     *
     * <UL>
     *   <LI><CODE>public static float intBitsToFloat(int bits)</CODE></LI>
     * </UL>
     *
     * @param s the int to convert to a float between -1 and +1
     * @return the resulting float
     * @see Float#intBitsToFloat(int)
     */
   public static float intToFloat(int s) {
        if (s == Integer.MIN_VALUE)
            return -1.0f;

        return ((float) s) / ((float) Integer.MAX_VALUE);
    }
    
    
    /**
     * <P>Returns the float between -1 and +1 calculated by dividing
     * the given long by <CODE>Long.MAX_VALUE</CODE>.</P>
     *
     * <P>The long <CODE>Long.MIN_VALUE</CODE> is treated as a special
     * case.  For this value, the method returns -1.</P>
     *
     * @param s the long to convert to a float between -1 and +1
     * @return the resulting float
     */
   public static float longToFloat(long s) {
        if (s == Long.MIN_VALUE)
            return -1.0f;

        return ((float) s) / ((float) Long.MAX_VALUE);
    }
    
    
    /**
     * <P>If the given float <CODE>x</CODE> is between -1 and +1,
     * then returns the value <CODE>x * Short.MAX_VALUE</CODE>
     * rounded to the nearest short.</P>
     *
     * <P>If the given float <CODE>x</CODE> is greater than or equal to +1,
     * then returns <CODE>Short.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given float <CODE>x</CODE> is less than or equal to -1,
     * then returns <CODE>-Short.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given float is NaN, returns 0.</P>
     *
     * @param x the float between -1 and +1 to convert to a short
     * @return the resulting short
     */
    public static short floatToShort(float x) {
        if (Float.isNaN(x))
            return 0;
        
        if (x >=  1.0f)
            return  Short.MAX_VALUE;
        
        if (x <= -1.0f)
            return -Short.MAX_VALUE;
        
        double z = (x * Short.MAX_VALUE) + 0.5;
        
        return (short) (Math.floor(z));
    }
    
    
    /**
     * <P>If the given float <CODE>x</CODE> is between -1 and +1,
     * then returns the value <CODE>x * Integer.MAX_VALUE</CODE>
     * rounded to the nearest int.</P>
     *
     * <P>If the given float <CODE>x</CODE> is greater than or equal to +1,
     * then returns <CODE>Integer.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given float <CODE>x</CODE> is less than or equal to -1,
     * then returns <CODE>-Integer.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given float is NaN, returns 0.</P>
     *
     * <P>The method intends to map a float between -1 and +1 to an int.
     * Its value is quite different from that of the following methods in
     * class <CODE>Float</CODE>:</P>
     *
     * <UL>
     *   <LI><CODE>public static int floatToIntBits(float value)</CODE></LI>
     *   <LI><CODE>public static int floatToRawIntBits(float value)</CODE></LI>
     * </UL>
     *
     * @param x the float between -1 and +1 to convert to an int
     * @return the resulting int
     * @see Float#floatToIntBits(float)
     * @see Float#floatToRawIntBits(float)
     */
    public static int floatToInt(float x) {
        if (Float.isNaN(x))
            return 0;
        
        if (x >=  1.0f)
            return  Integer.MAX_VALUE;
        
        if (x <= -1.0f)
            return -Integer.MAX_VALUE;
        
        double z = (x * Integer.MAX_VALUE) + 0.5;
        
        return (int) (Math.floor(z));
    }
    
    
    /**
     * <P>If the given float <CODE>x</CODE> is between -1 and +1,
     * then returns the value <CODE>x * Long.MAX_VALUE</CODE>
     * rounded to the nearest long.</P>
     *
     * <P>If the given float <CODE>x</CODE> is greater than or equal to +1,
     * then returns <CODE>Long.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given float <CODE>x</CODE> is less than or equal to -1,
     * then returns <CODE>-Long.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given float is NaN, returns 0.</P>
     *
     * @param x the float between -1 and +1 to convert to a long
     * @return the resulting long
     */
    public static long floatToLong(float x) {
        if (Float.isNaN(x))
            return 0;
        
        if (x >=  1.0f)
            return  Long.MAX_VALUE;
        
        if (x <= -1.0f)
            return -Long.MAX_VALUE;
        
        double z = (x * Long.MAX_VALUE) + 0.5;
        
        return (long) (Math.floor(z));
    }
    
    
    //////////////////
    // double tools //
    //////////////////
    
    /**
     * <P>Returns the double between -1 and +1 calculated by dividing
     * the given short by <CODE>Short.MAX_VALUE</CODE>.</P>
     *
     * <P>The short <CODE>Short.MIN_VALUE</CODE> is treated as a special
     * case.  For this value, the method returns -1.</P>
     *
     * @param s the short to convert to a double between -1 and +1
     * @return the resulting double
     */
   public static double shortToDouble(short s) {
        if (s == Short.MIN_VALUE)
            return -1.0;

        return ((double) s) / ((double) Short.MAX_VALUE);
    }
    
    
    /**
     * <P>Returns the double between -1 and +1 calculated by dividing
     * the given int by <CODE>Integer.MAX_VALUE</CODE>.</P>
     *
     * <P>The int <CODE>Integer.MIN_VALUE</CODE> is treated as a special
     * case.  For this value, the method returns -1.</P>
     *
     * @param s the int to convert to a double between -1 and +1
     * @return the resulting double
     */
   public static double intToDouble(int s) {
        if (s == Integer.MIN_VALUE)
            return -1.0;

        return ((double) s) / ((double) Integer.MAX_VALUE);
    }
    
    
    /**
     * <P>Returns the double between -1 and +1 calculated by dividing
     * the given long by <CODE>Long.MAX_VALUE</CODE>.</P>
     *
     * <P>The long <CODE>Long.MIN_VALUE</CODE> is treated as a special
     * case.  For this value, the method returns -1.</P>
     *
     * <P>The method intends to map a long to a double between -1 and +1.
     * Its value is quite different from that of the following method in
     * class <CODE>Double</CODE>:</P>
     *
     * <UL>
     *   <LI><CODE>public static double longBitsToDouble(long bits)</CODE></LI>
     * </UL>
     *
     * @param s the long to convert to a double between -1 and +1
     * @return the resulting double
     * @see Double#longBitsToDouble(long)
     */
   public static double longToDouble(long s) {
        if (s == Long.MIN_VALUE)
            return -1.0;

        return ((double) s) / ((double) Long.MAX_VALUE);
    }
    
    
    /**
     * <P>If the given double <CODE>x</CODE> is between -1 and +1,
     * then returns the value <CODE>x * Short.MAX_VALUE</CODE>
     * rounded to the nearest short.</P>
     *
     * <P>If the given double <CODE>x</CODE> is greater than or equal to +1,
     * then returns <CODE>Short.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given double <CODE>x</CODE> is less than or equal to -1,
     * then returns <CODE>-Short.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given double is NaN, returns 0.</P>
     *
     * @param x the double between -1 and +1 to convert to a short
     * @return the resulting short
     */
    public static short doubleToShort(double x) {
        if (Double.isNaN(x))
            return 0;
        
        if (x >=  1.0)
            return  Short.MAX_VALUE;
        
        if (x <= -1.0)
            return -Short.MAX_VALUE;
        
        double z = (x * Short.MAX_VALUE) + 0.5;
        
        return (short) (Math.floor(z));
    }
    
    
    /**
     * <P>If the given double <CODE>x</CODE> is between -1 and +1,
     * then returns the value <CODE>x * Integer.MAX_VALUE</CODE>
     * rounded to the nearest int.</P>
     *
     * <P>If the given double <CODE>x</CODE> is greater than or equal to +1,
     * then returns <CODE>Integer.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given double <CODE>x</CODE> is less than or equal to -1,
     * then returns <CODE>-Integer.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given double is NaN, returns 0.</P>
     *
     * @param x the double between -1 and +1 to convert to an int
     * @return the resulting int
     */
    public static int doubleToInt(double x) {
        if (Double.isNaN(x))
            return 0;
        
        if (x >=  1.0)
            return  Integer.MAX_VALUE;
        
        if (x <= -1.0)
            return -Integer.MAX_VALUE;
        
        double z = (x * Integer.MAX_VALUE) + 0.5;
        
        return (int) (Math.floor(z));
    }
    
    
    /**
     * <P>If the given double <CODE>x</CODE> is between -1 and +1,
     * then returns the value <CODE>x * Long.MAX_VALUE</CODE>
     * rounded to the nearest long.</P>
     *
     * <P>If the given double <CODE>x</CODE> is greater than or equal to +1,
     * then returns <CODE>Long.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given double <CODE>x</CODE> is less than or equal to -1,
     * then returns <CODE>-Long.MAX_VALUE</CODE>.</P>
     *
     * <P>If the given double is NaN, returns 0.</P>
     *
     * <P>The method intends to map a double between -1 and +1 to a long.
     * Its value is quite different from that of the following methods in
     * class <CODE>Double</CODE>:</P>
     *
     * <UL>
     *   <LI><CODE>public static long doubleToLongBits(double value)</CODE></LI>
     *   <LI><CODE>public static long doubleToRawLongBits(double value)</CODE></LI>
     * </UL>
     *
     * @param x the double between -1 and +1 to convert to a long
     * @return the resulting long
     * @see Double#doubleToLongBits(double)
     * @see Double#doubleToRawLongBits(double)
     */
    public static long doubleToLong(double x) {
        if (Double.isNaN(x))
            return 0;
        
        if (x >=  1.0)
            return  Long.MAX_VALUE;
        
        if (x <= -1.0)
            return -Long.MAX_VALUE;
        
        double z = (x * Long.MAX_VALUE) + 0.5;
        
        return (long) (Math.floor(z));
    }
    
}
