/*
* 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 javaforce.codec.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
};
}