#include "IQmathLib.h" // Преобразование числа с плавающей точкой в число с фиксированной точкой #define float_to_fixed(A) (long)((A)*(1 << (GLOBAL_Q)) + (A > 0 ? 0.5: -0.5)) // Преобразование числа с плавающей точкой в число с фиксированной точкой с выбором числа бит, отдаваемых под дробную часть #define float_to_fixed_base_select(A, F_BITS) (long)((A)*(1 << (F_BITS)) + (A > 0 ? 0.5: -0.5)) // Преобразование целого числа в число с фиксированной точкой #define int_to_fixed(A) (long)((A) << (GLOBAL_Q)) // Преобразование целого числа в число с фиксированной точкой с выбором числа бит, отдаваемых под дробную часть #define int_to_fixed_base_select(A, F_BITS) (long)((A) << (F_BITS)) //Преобразование числа с фиксированной точкой в число с плавающей точкой #define fixed_to_float(A) ((double)A / (1 << GLOBAL_Q)) //Перобразование числа с фиксированной точкой в целое число #define fixed_to_int(A) ((int)(A >> GLOBAL_Q) ) long multiply(long x, long y) { long long z = (long long)x * (long long)y; return (long)(z >> GLOBAL_Q); } //служебная функция. Умножает числа с 27 битами, отданными под дробную часть static inline long multiply_27(long x, long y) { long long z = (long long)x * (long long)y; return z & 0x4000000 ? (long)(z >> 27) + 1 : (long)(z >> 27); } long long multiply_fixed_base_select(long long x, long long y, int base) { long long z = (long long)x * (long long)y; return z & (1 << base) ? (z >> base) + 1 : (z >> base); } long divide(long num, long den) { long long numLong = (long long)num; long long quotient = (numLong << GLOBAL_Q) / den; return (long)quotient; } // static inline long long divide_fixed_base_select(long long num, long long den, int base) { long long quotient = ((long long)num << base) / den; return quotient; } #define div_def(A,B) (long)(((long long)(A) << 24)/(B)) #define div_mod(A,B) (A)%(B) #define mult_def(A,B) (long)((((long long)(A))*((long long)(B))) >> 24) #define abs_def(A) ((A) > 0 ? (A): -(A)) long sin_fixed(long x) { //Константы сделал ститическими, что бы они вычислялись во время запуска программы, а не исполнения static long FIXED_2PI = float_to_fixed(TWO_PI); static long FIXED_PI = float_to_fixed(PI); static long FIXED_PIna2 = float_to_fixed(PI_2); //Здесть так же что бы не производить операции деления посчитал констаны ряда Тейлора static long one_110 = float_to_fixed_base_select(1./110, 27); static long one_72 = float_to_fixed_base_select(1./72, 27); static long one_42 = float_to_fixed_base_select(1./42, 27); static long one_20= float_to_fixed_base_select(1./20, 27); static long one_6 = float_to_fixed_base_select(1./6, 27); long long xx, tmp ; while(x >= FIXED_2PI) { x -= FIXED_2PI;} //Помещаю аргумент в диапазон 2 ПИ while(x <= -FIXED_2PI) { x += FIXED_2PI;} //Так как ряды быстрее сходнятся при малых значениях, помещаю значение аргумента //в ближайшие к нулю области if(x > FIXED_PI) { x -= FIXED_2PI; } else if(x < -FIXED_PI) { x += FIXED_2PI; } if(x < -FIXED_PIna2) { x = -FIXED_PI - x; } else if(x > FIXED_PIna2) { x = FIXED_PI - x; } //проверяю угол на значения, при которых синус раве 0 или 1 if(x == 0) return 0; if(x == FIXED_PIna2) return int_to_fixed(1); if(x == -FIXED_PIna2) return int_to_fixed(-1); //Перевожу в формат с максимальной точностью для возможного дипазано значений x <<= (27 - GLOBAL_Q); //Считаю ряд фурье xx = multiply_27(x, x); tmp = ONE_27 - multiply_27(one_110, xx); tmp = multiply_27(xx, tmp); tmp = ONE_27 - multiply_27(tmp, one_72); tmp = multiply_27(xx, tmp); tmp = ONE_27 - multiply_27(tmp, one_42); tmp = multiply_27(xx, tmp); tmp = ONE_27 - multiply_27(tmp, one_20); tmp = multiply_27(xx, tmp); tmp = ONE_27 - multiply_27(tmp, one_6); tmp = multiply_27(x, tmp); return tmp >> (27 - GLOBAL_Q); //Перед возвращением из функции преобразую в первоначальный формат } long cos_fixed(long x) { //Константы сделал ститическими, что бы они вычислялись во время запуска программы, а не исполнения static long FIXED_2PI = float_to_fixed(TWO_PI); static long FIXED_PI = float_to_fixed(PI); static long FIXED_PIna2 = float_to_fixed(PI_2); //Здесть так же что бы не производить операции деления посчитал констаны ряда Тейлора static long one_132 = float_to_fixed_base_select(1./132, 27); static long one_90 = float_to_fixed_base_select(1./90, 27); static long one_56 = float_to_fixed_base_select(1./56, 27); static long one_30 = float_to_fixed_base_select(1./30, 27); static long one_12 = float_to_fixed_base_select(1./12, 27); long xx, tmp, counter = 0; while(x >= FIXED_2PI) { x -= FIXED_2PI;} //Помещаю аргумент в диапазон 2 ПИ while(x < 0) { x += FIXED_2PI;} x = _IQabs(x); //Так как косинус симметричен относительно нуля, нахожу его модуль //проверяю угол на значения, при которых синус раве 0 или 1 if(x == 0) return 1 << GLOBAL_Q; if(x == FIXED_PI) return -(1 << GLOBAL_Q); if(x == (FIXED_PIna2) || (x == FIXED_3PIna2))return 0; //Так как ряды быстрее сходнятся при малых значениях, помещаю значение аргумента //в ближайшие к нулю области while(x > FIXED_PIna2) { x -= FIXED_PIna2; counter++; } if(counter == 1 || counter == 3) { x = FIXED_PIna2 - x;} //Перевожу в формат с максимальной точностью для возможного дипазона значений x <<= (27 - GLOBAL_Q); //Считаю ряд фурье xx = multiply_27(x, x); tmp = ONE_27 - multiply_27(xx, one_132); tmp= multiply_27(xx, tmp); tmp = ONE_27 - multiply_27(xx, one_90); tmp= multiply_27(xx, tmp); tmp = ONE_27 - multiply_27(tmp, one_56); tmp = multiply_27(xx, tmp); tmp = ONE_27 - multiply_27(tmp, one_30); tmp = multiply_27(xx, tmp); tmp = ONE_27 - multiply_27(tmp, one_12); tmp = multiply_27(xx, tmp); tmp = ONE_27 - (tmp >> 1); tmp >>= (27 - GLOBAL_Q); return (counter == 0) || (counter == 3) ? tmp : -tmp; } long sqrt_fixed(long x) { int variable_size_bits = sizeof(x) << 3; long average_val, prev_avg_val; if(x <= 0) return 0; while(!(x & (1 << --variable_size_bits))); //Нахожу старший значащий бит //Нахожу приближение корня сдвгом на половину числа бит между старшим значащим битом //и положением точки if(variable_size_bits > GLOBAL_Q) { average_val = x >> ((variable_size_bits - GLOBAL_Q) >> 1); } else { average_val = x << ((GLOBAL_Q - variable_size_bits) >> 1); } prev_avg_val = divide(x, average_val); //Нахожу 1/А //В цикле нахожу среднее арифметическое между А и 1/А, пока число не перестанет меняться while(_IQabs(prev_avg_val - average_val) > 1) { prev_avg_val = average_val; average_val = (average_val + divide(x, average_val)) >> 1; } return average_val; }