/*
* Mathmatical methods.
* Copyright (C) 1999 Christopher Edwards
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package org.tritonus.lowlevel.gsm;
public class Add
{
public static short saturate(int x)
{
return (short) ((x) < Gsm_Def.MIN_WORD ? Gsm_Def.MIN_WORD :
(x) > Gsm_Def.MAX_WORD ? Gsm_Def.MAX_WORD: (x));
}
public static short saturate(long x)
{
return (short) ((x) < Gsm_Def.MIN_WORD ? Gsm_Def.MIN_WORD :
(x) > Gsm_Def.MAX_WORD ? Gsm_Def.MAX_WORD: (x));
}
public static short SASR(int x, int by)
{
return (short) ((x) >> (by));
}
public static short GSM_ADD(short a, short b)
{
/*
* This converts a and b to int implicitely, because
* '+' is not defined for short.
*/
int sum = a + b;
return saturate(sum);
}
public static short GSM_SUB(short a, short b)
{
/*
* This converts a and b to int implicitely, because
* '-' is not defined for short.
*/
int diff = a - b;
return saturate(diff);
}
public static short GSM_MULT(short a, short b)
{
if (a == Gsm_Def.MIN_WORD && b == Gsm_Def.MIN_WORD)
{
return Gsm_Def.MAX_WORD;
}
else
{
return SASR( ((int)(a)) * ((int)(b)), 15 );
}
}
public static short GSM_MULT_R(short a, short b)
{
if (a == Gsm_Def.MIN_WORD && b == Gsm_Def.MIN_WORD)
{
return Gsm_Def.MAX_WORD;
}
else
{
int prod = (int) (((int)(a)) * ((int)(b)) + 16384);
prod >>= 15;
return (short) (prod & 0xFFFF);
}
}
public static short GSM_ABS(short a)
{
int b = a < 0 ? (a == Gsm_Def.MIN_WORD ? Gsm_Def.MAX_WORD : -a) : a;
return ((short)(b));
}
public static int GSM_L_MULT(short a, short b)
throws IllegalArgumentException
{
if( a != Short.MIN_VALUE || b != Short.MIN_VALUE )
{
throw new IllegalArgumentException(
"One of the aruments must equal " + Short.MIN_VALUE);
}
return ((int)a * (int)b) << 1;
}
public static int GSM_L_ADD(int a, int b)
{
if (a <= 0)
{
if (b >= 0)
{
return a + b;
}
else
{
long A = (long)-(a + 1) + (long)-(b + 1);
return A >= Gsm_Def.MAX_LONGWORD ? Gsm_Def.MIN_LONGWORD :-(int)A-2;
}
}
else if (b <= 0)
{
return a + b;
}
else
{
long A = (long)a + (long)
b;
return (int)(A > Gsm_Def.MAX_LONGWORD ? Gsm_Def.MAX_LONGWORD : A);
}
}
/*
* the number of left shifts needed to normalize the 32 bit
* variable L_var1 for positive values on the interval
*
* with minimum of
* minimum of 1073741824 (01000000000000000000000000000000) and
* maximum of 2147483647 (01111111111111111111111111111111)
*
*
* and for negative values on the interval with
* minimum of -2147483648 (-10000000000000000000000000000000) and
* maximum of -1073741824 ( -1000000000000000000000000000000).
*
* in order to normalize the result, the following
* operation must be done: L_norm_var1 = L_var1 << norm( L_var1 );
*
* (That's 'ffs', only from the left, not the right..)
*/
public static short gsm_norm( int a )
throws IllegalArgumentException
{
if(a == 0)
{
throw new IllegalArgumentException
("gsm_norm: a cannot = 0.");
}
if (a < 0)
{
if (a <= -1073741824)
{
return 0;
}
a = ~a;
}
return (short) ( ((a & 0xffff0000) != 0)
? ( ((a & 0xff000000) != 0)
? -1 + bitoff[ (int)(0xFF & (a >> 24)) ]
: 7 + bitoff[ (int)(0xFF & (a >> 16)) ] )
: ( ((a & 0xff00) != 0)
? 15 + bitoff[ (int)(0xFF & (a >> 8)) ]
: 23 + bitoff[ (int)(0xFF & a) ] ));
}
public static short gsm_asl(short a, int n)
{
if (n >= 16) return ((short) 0);
if (n <= -16)
if(a<0)
return (short) -1;
else
return (short) -0;
if (n < 0) return gsm_asr(a, -n);
return ((short)( a << n ));
}
public static short gsm_asr(short a, int n)
{
if (n >= 16)
if(a<0)
return (short) -1;
else
return (short) -0;
if (n <= -16) return ((short) 0);
if (n < 0) return ((short)( a << -n ));
return ((short)( a >> n ));
}
public static short gsm_div(short num, short denum)
throws IllegalArgumentException
{
int L_num = num;
int L_denum = denum;
short div = 0;
int k = 15;
/* The parameter num sometimes becomes zero.
* Although this is explicitly guarded against in 4.2.5,
* we assume that the result should then be zero as well.
*/
/* assert(num != 0); */
if( ! (num >= 0 && denum >= num) )
{
throw new IllegalArgumentException
("gsm_div: num >= 0 && denum >= num");
}
if (num == 0)
return 0;
while (k != 0)
{
k--;
div <<= 1;
L_num <<= 1;
if (L_num >= L_denum)
{
L_num -= L_denum;
div++;
}
}
return div;
}
private static final short bitoff[] =
{
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
}