Vallen2006 0 20 июля, 2009 Опубликовано 20 июля, 2009 · Жалоба Доброго времени суток! Только начал заниматься процессорами BlackFin и обработкой сигналов, возник вопрос такой. Используя тип fract16 пишу код: fract16 data; data = float_to_fract16(0.0); printf("data = %f, data = 0x%x\n", fract16_to_float(data), (unsigned short)data); Получаю на выходе data = -0.000005, data = 0x0 т.е. число 0 при расшифровке становиться -0.000005. Самое интересное, что когда считаю дисперсию сигнала она тоже может получиться отрицательной. Никто не сталкивался с подобным? Как можно обойти данную проблему? Поможет ли изменение _MAX_FLOAT_RANGE для преобразования в fract16 и обратно? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
fontp 0 20 июля, 2009 Опубликовано 20 июля, 2009 · Жалоба Доброго времени суток! Только начал заниматься процессорами BlackFin и обработкой сигналов, возник вопрос такой. Используя тип fract16 пишу код: fract16 data; data = float_to_fract16(0.0); printf("data = %f, data = 0x%x\n", fract16_to_float(data), (unsigned short)data); Получаю на выходе data = -0.000005, data = 0x0 т.е. число 0 при расшифровке становиться -0.000005. Самое интересное, что когда считаю дисперсию сигнала она тоже может получиться отрицательной. Никто не сталкивался с подобным? Как можно обойти данную проблему? Поможет ли изменение _MAX_FLOAT_RANGE для преобразования в fract16 и обратно? означает, что fract16_to_float имеет ошибку преобразования 0 во float -0.000005 (верю Вам на слово и не проверяю) Что меньше, вообще говоря, стандартного отклонения ошибки при представлении чисел с помощью fract16 (там что-то порядка 2 на 10**-5). В принципе ничего страшного, хотя неприятно, главное, что хоть 0+0+0+0 ... = 0 пускай себе fract16_to_float(0) + fract16_to_float(0)+fract16_to_float(0)... стремится к бесконечности B) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Vallen2006 0 20 июля, 2009 Опубликовано 20 июля, 2009 · Жалоба означает, что fract16_to_float имеет ошибку преобразования 0 во float -0.000005 (верю Вам на слово и не проверяю) Что меньше, вообще говоря, стандартного отклонения ошибки при представлении чисел с помощью fract16 (там что-то порядка 2 на 10**-5). В принципе ничего страшного, хотя неприятно, главное, что хоть 0+0+0+0 ... = 0 пускай себе fract16_to_float(0) + fract16_to_float(0)+fract16_to_float(0)... стремится к бесконечности B) Спасибо. Понятно, только получается что 0+0+0... = 0, но после преобразования в float получаю отрицательное число, и что мне с ним дальше делать если нужно посчитать сигму (т.е. корень квадратный из него)? И еще тогда вопрос, если есь ошибка преобразования fract16 -> float, то почему нет float -> fract16. Может необходимо изменить диапазон значений преобразуемых величин? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vik0 0 20 июля, 2009 Опубликовано 20 июля, 2009 · Жалоба Поможет ли изменение _MAX_FLOAT_RANGE для преобразования в fract16 и обратно? Категорически не стоит менять что-либо в системных заголовочных файлах. На 99.9(9)% это не решит проблему, а только добавит новые. ...и что мне с ним дальше делать если нужно посчитать сигму (т.е. корень квадратный из него)? А зачем преобразовывать во float? Берите корень из fract. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
andrewn 0 21 июля, 2009 Опубликовано 21 июля, 2009 · Жалоба число 0 при расшифровке становиться -0.000005. Однажды я столкнулся с подобным при тестировании FastMath - симулятора арифметики с плавающей точкой для C62xx/C64xx. Все работало неплохо, вот только 2.0 * 0.0 = 2.0. Такой вот специфичный баг. Оказалось, что программист слегка промахнулся при вычислении экспоненты произведения. В вашем случае что-то похожее, только программист, по-видимому, перестарался с обработкой ошибки округления в преобразовании, а её тут вообще нет, любое Q16.xx _точно_ содержится в 32-битном float. Напишите в Аналог, что у них завелся таракан. Пока они будут думать, обойти можно примерно так, для Q16.15: float corrected_fract16_to_float (fract16 f) { int s, e, m; short x = (short) f; if (x == 0) return (0.0f); // test input is zero s = (x & 0x8000) << 16; // extract sign m = (s) ? -x : x; // mantissa seed (positive) e = 0x7F; // biased exp seed while (!(m & 0x8000)) // find msb { e = e - 1; // decrement exp m = m << 1; // shift msntissa } e = e << 23; // shift exp in place m = (m & 0x7FFF) << 8; // remove mantissa implicit bit m = (s | e | m); // assemble result return (*(float *)&m); // done } Ради любопытства, вы можете распечатать на 4 чиcла больше: float r; r = fract16_to_float (0x0000); printf ("zero 0x%8X \n", *(int *)&r); r = fract16_to_float (0x8000); printf("neg one 0x%8X \n", *(int *)&r); r = fract16_to_float (0x4000); printf ("half 0x%8X \n", *(int *)&r); r = fract16_to_float (0x2000); printf ("quarter 0x%8X \n", *(int *)&r); r = fract16_to_float (0x1000); printf ("eighth 0x%8X \n", *(int *)&r); P.S. изменение _MAX_FLOAT_RANGE не поможет, проблема в неправильном округлении а не в диапазоне входных чисел. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Vallen2006 0 21 июля, 2009 Опубликовано 21 июля, 2009 · Жалоба Однажды я столкнулся с подобным при тестировании FastMath - симулятора арифметики с плавающей точкой для C62xx/C64xx. Все работало неплохо, вот только 2.0 * 0.0 = 2.0. Такой вот специфичный баг. Оказалось, что программист слегка промахнулся при вычислении экспоненты произведения. В вашем случае что-то похожее, только программист, по-видимому, перестарался с обработкой ошибки округления в преобразовании, а её тут вообще нет, любое Q16.xx _точно_ содержится в 32-битном float. Напишите в Аналог, что у них завелся таракан. Пока они будут думать, обойти можно примерно так, для Q16.15: float corrected_fract16_to_float (fract16 f) { int s, e, m; short x = (short) f; if (x == 0) return (0.0f); // test input is zero s = (x & 0x8000) << 16; // extract sign m = (s) ? -x : x; // mantissa seed (positive) e = 0x7F; // biased exp seed while (!(m & 0x8000)) // find msb { e = e - 1; // decrement exp m = m << 1; // shift msntissa } e = e << 23; // shift exp in place m = (m & 0x7FFF) << 8; // remove mantissa implicit bit m = (s | e | m); // assemble result return (*(float *)&m); // done } Ради любопытства, вы можете распечатать на 4 чиcла больше: float r; r = fract16_to_float (0x0000); printf ("zero 0x%8X \n", *(int *)&r); r = fract16_to_float (0x8000); printf("neg one 0x%8X \n", *(int *)&r); r = fract16_to_float (0x4000); printf ("half 0x%8X \n", *(int *)&r); r = fract16_to_float (0x2000); printf ("quarter 0x%8X \n", *(int *)&r); r = fract16_to_float (0x1000); printf ("eighth 0x%8X \n", *(int *)&r); P.S. изменение _MAX_FLOAT_RANGE не поможет, проблема в неправильном округлении а не в диапазоне входных чисел. Спасибо. Вывод данных: r = fract16_to_float(0x0000); printf ("zero 0x%8X \n", *(int *)&r); r = fract16_to_float(0x8000); printf ("zero 0x%8X \n", *(int *)&r); r = fract16_to_float(0x4000); printf ("zero 0x%8X \n", *(int *)&r); r = fract16_to_float(0x2000); printf ("zero 0x%8X \n", *(int *)&r); r = fract16_to_float(0x1000); printf ("zero 0x%8X \n", *(int *)&r); r = fract16_to_float(0x0000); printf ("zero 0x%8X \n", *(unsigned short *)&r); r = fract16_to_float(0x8000); printf ("zero 0x%8X \n", *(unsigned short *)&r); r = fract16_to_float(0x4000); printf ("zero 0x%8X \n", *(unsigned short *)&r); r = fract16_to_float(0x2000); printf ("zero 0x%8X \n", *(unsigned short *)&r); r = fract16_to_float(0x1000); printf ("zero 0x%8X \n", *(unsigned short *)&r); zero 0xB6980000 zero 0xBF800000 zero 0x3EFFFF1C zero 0x3E7FFE84 zero 0x3DFFFD54 zero 0x 0 zero 0x 0 zero 0x FF1C zero 0x FE84 zero 0x FD54 Вопрос по _MAX_FLOAT_RANGE возник вот почему: пределы чисел и преобразования определены так /* * The following constants describe the properties of a * scaled floating point range, equivalent to the range * for fract16 values between 0x8000 and 0x7fff * ==>> DO NOT MODIFY */ #define _MIN_FRACT_RANGE ( -1.0 ) #define _MAX_FRACT_RANGE ( 0.999969 ) #define _RANGE_FRACT ( -_MIN_FRACT_RANGE + _MAX_FRACT_RANGE ) /* * The following data are to be supplied by the user. * They describe the original data set * ==>> TO BE MODIFIED */ #define _MIN_FLOAT_RANGE ( -1.0 ) #define _MAX_FLOAT_RANGE ( 0.99996 ) #define _RANGE_X ( -_MIN_FLOAT_RANGE + _MAX_FLOAT_RANGE ) /* * The following macros are used by the conversion functions * ==>> DO NOT MODIFY */ #define _TERM_A (_RANGE_FRACT / _RANGE_X) #define _TERM_B ((-_MIN_FLOAT_RANGE * _TERM_A) + _MIN_FRACT_RANGE ) #define _TERM_a (_RANGE_X / _RANGE_FRACT) #define _TERM_b ((-_MIN_FRACT_RANGE * _TERM_a) + _MIN_FLOAT_RANGE ) #define _INV_2_POW_15 (1.0 / 32768.0) /* Function to convert floating point data into fract16 data */ #pragma inline #pragma always_inline fract16 float_to_fract16(float _x) { float val = ( ( (_x * _TERM_A) + _TERM_B ) * 32768.0 ); return (fract16)val; } /* Function to convert fract16 data into floating point data */ #pragma inline #pragma always_inline float fract16_to_float(fract16 _x16) { return ( (((double)_x16 * _TERM_a) * _INV_2_POW_15) + _TERM_b ); } т.е. диапазон float и fract16 не совпадают, что приводит к масштабированию и сдвигу числа при преобразовании. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
andrewn 0 21 июля, 2009 Опубликовано 21 июля, 2009 · Жалоба [snip] диапазон float и fract16 не совпадают, что приводит к масштабированию и сдвигу числа при преобразовании. 0: 0xB6980000 должно быть 0x00000000 -1: 0xBF800000 должно быть 0xBF800000 1/2: 0x3EFFFF1C должно быть 0x3F000000 1/4: 0x3E7FFE84 должно быть 0x3E800000 1/8: 0x3DFFFD54 должно быть 0x3E000000 Из пяти чисел только одно преобразуется без ошибки, -1. Что и следует из применённого метода. Сценарий из логики кода, на мой взгляд, довольно странный: исходные данные в плавающей точке, принадлежащие произвольному интервалу, приводятся к фиксированной точке на интервале [-1,1), обрабатываются в Q16.15 и преобразуются обратно к исходному интервалу. Что влечёт огрубление и без того ошибочных исходных данных, увеличение погрешности вследствие произведённых арифметических операций в фиксированной точке и, наконец, дополнительная ошибка при обратном преобразовании в плавающую точку. Более логичным представляется сценарий "наоборот": исходные данные на интервале [-1,1) в Q16.15 - например, отсчёты АЦП. Эти данные преобразуются к плавающей точке, тем самым повышается точность представления чисел, считаются в плавающей точке, нормируя результаты так, что бы они (по возможности) не выходили за пределы исходного интервала и окончательный результат преобразуется к фиксированной точке - (огрубляя его, конечно) - например для вывода в ЦАП. При таком методе приведение интервалов не нужно и преобразование fract16 -> float будет точным. Обратное, в общем, неверно, но числа, имеющие точное представление в Q16.15 [0, +/-1/2, +/-1/4, +/-(1/2 + 1/4), ..., -1] будут преобразованы точно. Конечно, считать float на целочисленной машине медленно, но не в этом же дело, в самом деле? Лучше медленно с неотрицательной дисперсией, чем быстро с новым словом в статистике и двойкой в зачётке :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Vallen2006 0 22 июля, 2009 Опубликовано 22 июля, 2009 · Жалоба 0: 0xB6980000 должно быть 0x00000000 -1: 0xBF800000 должно быть 0xBF800000 1/2: 0x3EFFFF1C должно быть 0x3F000000 1/4: 0x3E7FFE84 должно быть 0x3E800000 1/8: 0x3DFFFD54 должно быть 0x3E000000 Из пяти чисел только одно преобразуется без ошибки, -1. Что и следует из применённого метода. Сценарий из логики кода, на мой взгляд, довольно странный: исходные данные в плавающей точке, принадлежащие произвольному интервалу, приводятся к фиксированной точке на интервале [-1,1), обрабатываются в Q16.15 и преобразуются обратно к исходному интервалу. Что влечёт огрубление и без того ошибочных исходных данных, увеличение погрешности вследствие произведённых арифметических операций в фиксированной точке и, наконец, дополнительная ошибка при обратном преобразовании в плавающую точку. Более логичным представляется сценарий "наоборот": исходные данные на интервале [-1,1) в Q16.15 - например, отсчёты АЦП. Эти данные преобразуются к плавающей точке, тем самым повышается точность представления чисел, считаются в плавающей точке, нормируя результаты так, что бы они (по возможности) не выходили за пределы исходного интервала и окончательный результат преобразуется к фиксированной точке - (огрубляя его, конечно) - например для вывода в ЦАП. При таком методе приведение интервалов не нужно и преобразование fract16 -> float будет точным. Обратное, в общем, неверно, но числа, имеющие точное представление в Q16.15 [0, +/-1/2, +/-1/4, +/-(1/2 + 1/4), ..., -1] будут преобразованы точно. Конечно, считать float на целочисленной машине медленно, но не в этом же дело, в самом деле? Лучше медленно с неотрицательной дисперсией, чем быстро с новым словом в статистике и двойкой в зачётке :) Немного ошибся в пердыдущем посте r = fract16_to_float(0x0000); r1 = float_to_fract16®; printf ("zero 0x%8X \n", *(unsigned short *)&r1); r = fract16_to_float(0x8000); r1 = float_to_fract16®; printf ("zero 0x%8X \n", *(unsigned short *)&r1); r = fract16_to_float(0x4000); r1 = float_to_fract16®; printf ("zero 0x%8X \n", *(unsigned short *)&r1); r = fract16_to_float(0x2000); r1 = float_to_fract16®; printf ("zero 0x%8X \n", *(unsigned short *)&r1); r = fract16_to_float(0x1000); r1 = float_to_fract16®; printf ("zero 0x%8X \n", *(unsigned short *)&r1); zero 0x 0 zero 0x 8000 zero 0x 4000 zero 0x 2000 zero 0x 1000 Насчет кода преобразования, так он стандартный (для Analog). Считать с плавующей точкой не успею, т.к. цикл 5 мс, а данных обработать надо много. Буду думать. Кстати при изменении даипазона _MAX_FLOAT_RANGE = 0.999969 Вывод меняется на более вменяемый: zero 0x 0 zero 0xBF800000 zero 0x3F000000 zero 0x3E800000 zero 0x3E000000 Интересно диапазон изменен Analog-ом с какой-то целью или нет? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vik0 0 22 июля, 2009 Опубликовано 22 июля, 2009 · Жалоба Считать с плавующей точкой не успею, т.к. цикл 5 мс, а данных обработать надо много. fastfloat видели? Может подойдет для ваших целей. А вообще вы точно уверены что выбрали (если конечно выбирали вы) правильный процессор? Интересно диапазон изменен Analog-ом с какой-то целью или нет? Спросите у support-а, он у них весьма адекватный. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
fontp 0 22 июля, 2009 Опубликовано 22 июля, 2009 · Жалоба Ну, индусы в Бангалоре так видят ;-) Методически последовательно, а для каких-то практических целей вполне адекватно. Мало ли что Вы ожидаете, что результат >=0? Там ошибка округления. Интерпретируйте как if (x<0) x=0 Кстати при вычислении во float тоже легко можно получить отрицательный результат, там где ожидается положительный. (S+a*a) - S легко может оказаться меньше 0 и вызвать изумление. Я вот что подумал. Зачем Вам вообще тот fixed-tо-float. Очевидно, что правильный fixed_to_float(X) - это X/32768. Где X интерпретируется просто как целое число. Труднее обойтись без деления, немного подумать надо В fastfloat32 (fastfloat16) индусы, если не ошибаюсь, обошлись )) Но underflow (потерю точности) игнорируют, зачем обработка потери точности в программе риал-тайм? Не пересчитывать же всё заново, когда всё пропало B) Разве что при отладке... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
andrewn 0 23 июля, 2009 Опубликовано 23 июля, 2009 (изменено) · Жалоба Кстати при вычислении во float тоже легко можно получить отрицательный результат, там где ожидается положительный. (S+a*a) - S легко может оказаться меньше 0 и вызвать изумление. Точнее сказать, что результат может отклонится от ожидаемого на малую величину (для устойчивого алгоритма). Следовательно, отрицательное число может появиться _только_ если результат ожидается равным нулю. Если ожидается число не равное нулю, то знак результата _должен_ совпадать со знаком ожидаемого числа. "Это элементарно в стандарте IEEE754" :) Например, (S+a*a) - S: Как обычно, eps = min(x): x > 0 и 1 + x > 1, представимое в формате плавающей точки. 1. Допустим что a*a < eps*|S|. Следовательно (S+a*a) == S и значение выражения точно равно нулю. Если |S| == 0 или eps*|S| денормализованное, т.е. округляется до нуля, то из неотрицательности a*a (что гарантируется в IEEE754) следует, что a*a == 0 и значение выражения остаётся равным нулю. 2. Допустим что a*a >= eps*|S|. Следовательно a*a > 0 и (S+a*a) > S. Отсюда следует, что независимо от знака S значение выражения > 0. Изменено 23 июля, 2009 пользователем AndrewN Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться