/* * SpanDSP - a series of DSP components for telephony * * math_fixed.c * * Written by Steve Underwood * * Copyright (C) 2010 Steve Underwood * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 2.1, * as published by the Free Software Foundation. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /*! \file */ #if defined(HAVE_CONFIG_H) #include "config.h" #endif #include #include #include #include #include #include #if defined(HAVE_TGMATH_H) #include #endif #if defined(HAVE_MATH_H) #include #endif #include "floating_fudge.h" #include #include "math_fixed_tables.h" #include "spandsp/telephony.h" #include "spandsp/bit_operations.h" #include "spandsp/math_fixed.h" #if defined(SPANDSP_USE_FIXED_POINT) SPAN_DECLARE(uint16_t) sqrtu32_u16(uint32_t x) { uint16_t zz; uint16_t z; uint16_t i; z = 0; for (i = 0x8000; i; i >>= 1) { zz = z | i; if (((int32_t) zz*zz) <= x) z = zz; } return z; } /*- End of function --------------------------------------------------------*/ #endif SPAN_DECLARE(uint16_t) fixed_reciprocal16(uint16_t x, int *shift) { if (x == 0) { *shift = 0; return 0xFFFF; } *shift = 15 - top_bit(x); x <<= *shift; return fixed_reciprocal_table[((x + 0x80) >> 8) - 128]; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(uint16_t) fixed_divide16(uint16_t y, uint16_t x) { int shift; uint32_t z; uint16_t recip; if (x == 0) return 0xFFFF; recip = fixed_reciprocal16(x, &shift); z = (((uint32_t) y*recip) >> 15) << shift; return z; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(uint16_t) fixed_divide32(uint32_t y, uint16_t x) { int shift; uint32_t z; uint16_t recip; if (x == 0) return 0xFFFF; recip = fixed_reciprocal16(x, &shift); z = (((uint32_t) y*recip) >> 15) << shift; return z; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int16_t) fixed_log10_16(uint16_t x) { int shift; if (x == 0) return 0; shift = 14 - top_bit(x); x <<= shift; return (fixed_log10_table[((x + 0x40) >> 7) - 128] >> 3) - shift*1233; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int32_t) fixed_log10_32(uint32_t x) { int shift; if (x == 0) return 0; shift = 30 - top_bit(x); x <<= shift; return (fixed_log10_table[((x + 0x400000) >> 23) - 128] >> 3) - shift*1233; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(uint16_t) fixed_sqrt16(uint16_t x) { int shift; if (x == 0) return 0; shift = 14 - (top_bit(x) & ~1); x <<= shift; //return fixed_sqrt_table[(((x + 0x80) >> 8) & 0xFF) - 64] >> (shift >> 1); return fixed_sqrt_table[((x >> 8) & 0xFF) - 64] >> (shift >> 1); } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(uint16_t) fixed_sqrt32(uint32_t x) { int shift; if (x == 0) return 0; shift = 30 - (top_bit(x) & ~1); x <<= shift; //return fixed_sqrt_table[(((x + 0x800000) >> 24) & 0xFF) - 64] >> (shift >> 1); return fixed_sqrt_table[((x >> 24) & 0xFF) - 64] >> (shift >> 1); } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int16_t) fixed_sin(uint16_t x) { int step; int step_after; int16_t frac; int16_t z; step = (x & 0x3FFF) >> 6; frac = x & 0x3F; if ((x & 0x4000)) { step = 256 - step; step_after = step - 1; } else { step_after = step + 1; } z = fixed_sine_table[step] + ((frac*(fixed_sine_table[step_after] - fixed_sine_table[step])) >> 6); if ((x & 0x8000)) z = -z; return z; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int16_t) fixed_cos(uint16_t x) { int step; int step_after; int16_t frac; int16_t z; x += 0x4000; step = (x & 0x3FFF) >> 6; frac = x & 0x3F; if ((x & 0x4000)) { step = 256 - step; step_after = step - 1; } else { step_after = step + 1; } z = fixed_sine_table[step] + ((frac*(fixed_sine_table[step_after] - fixed_sine_table[step])) >> 6); if ((x & 0x8000)) z = -z; return z; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(uint16_t) fixed_atan2(int16_t y, int16_t x) { int16_t abs_x; int16_t abs_y; uint16_t angle; uint16_t recip; uint32_t z; int step; int shift; if (y == 0) return (x & 0x8000); if (x == 0) return ((y & 0x8000) | 0x4000); abs_x = abs(x); abs_y = abs(y); if (abs_y < abs_x) { recip = fixed_reciprocal16(abs_x, &shift); z = (((uint32_t) recip*abs_y) >> 15) << shift; step = z >> 7; angle = fixed_arctan_table[step]; } else { recip = fixed_reciprocal16(abs_y, &shift); z = (((uint32_t) recip*abs_x) >> 15) << shift; step = z >> 7; angle = 0x4000 - fixed_arctan_table[step]; } /* If we are in quadrant II or III, flip things around */ if (x < 0) angle = 0x8000 - angle; /* If we are in quadrant III or IV, negate to return an answer in the full circle range. */ if (y < 0) angle = -angle; return (uint16_t) angle; } /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/