sigmaN 0 17 марта, 2015 Опубликовано 17 марта, 2015 · Жалоба С преобразованием целой части все ясно. По поводу дробной пока размышляю так: К примеру имеем Q8.8 = 1 Т.е. в строку надо вывести 1/256 т.е. 0,00390625 Как этого добиться? К примеру хотим вывести с точностью до 4 знаков. FracAsInt = 1 * 10000 / 256 = 39 (операции целочисленные) Мы потеряли два нуля, но если делать эту операцию в цикле, последовательно, сначала умножить на 10 потом на 100 и т.д. до нужного кол-ва знаков. Нули выловить таким образом можно. Помимо общей корявости тут есть проблемка. А что если выводить придется Q0.32 до восемнадцатого знака после точки(ну предположим вот надо) так ведь можно и 64бита переполнить с таким алгоритмом... Как это делается по правильному? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Xenia 35 17 марта, 2015 Опубликовано 17 марта, 2015 · Жалоба Как это делается по правильному? Как надо правильно, не знаю. Я же сама алгоритм сочиняла. Получилось вот так: void PushFix( long val, long divisor, unsigned char fix) { ldiv_t temp; if( val >= 0) temp = ldiv( val, divisor); else { temp = ldiv( -val, divisor); temp.quot = -temp.quot; } PushLong( temp.quot); Push( '.'); unsigned long base; switch( fix) { case 1: base=10; break; case 2: base=100; break; case 3: base=1000; break; case 4: base=10000; break; case 5: base=100000; break; default: return; } char str[11]; unsigned char len; val = temp.rem * base / divisor; ltoa( val, str, 10); len = strlen( str); while( len++ < fix) Push( '0'); PushStr( str); } где: PushFix( long val, long divisor, unsigned char fix); // числитель, знаменатель, число знаков после запятой (< 6) PushLong(long); // печатает длинное целое Push(char); // печатает символ PushStr(char*); // печатает строку символов (на самом деле они у меня не на печать выводятся, а сперва в буфер засоваются - отсюда и названия Push+). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 17 марта, 2015 Опубликовано 17 марта, 2015 · Жалоба А что если выводить придется Q0.32 до восемнадцатого знака после точки(ну предположим вот надо) так ведь можно и 64бита переполнить с таким алгоритмом.. В чём проблема? Умножаете на 10, выводите цифру, вычитаете её из числа, далее - след. цифра и т.д. Как тут можно переполнить 64???? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 17 марта, 2015 Опубликовано 17 марта, 2015 · Жалоба Хмм, вычитаать... Надо попробовать однако) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 18 марта, 2015 Опубликовано 18 марта, 2015 · Жалоба Хмм, вычитаать...Даже вычитать не надо - просто отбрасываете целую часть Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 20 марта, 2015 Опубликовано 20 марта, 2015 · Жалоба В общем вычитать что и куда я немного не понял... сделал так: for( uint8_t i = 0; i < fracDigits; i++ ) { T digit = frac * 10 / POW2F; fracBuf[i] = digit + '0'; frac = frac * 10 % POW2F; } Перемудрил? На первой итерации frac = значение дробной части FixedPoint переменной, полученное из нее с помощью битовой маски. fracDigits - требуемое кол-во знаков после точки. fracBuf[] строка POW2F - 2 в степени кол-во бит дробной части. т.е. для Q8.8 это будет 2^8 T - тип, метод шаблонный.... Для целой части всё стандартно, там ведь просто преобразование int в строку. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 20 марта, 2015 Опубликовано 20 марта, 2015 · Жалоба Что-ж тут непонятного??? //arg - в формате Q0.32 void f(u32 arg) { if (!arg) return; putc('.'); for (int i = 10; --i >= 0; arg = k) { u64 k = (u64)arg * 10; putc((u32)(k >> 32) + '0'); } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 20 марта, 2015 Опубликовано 20 марта, 2015 · Жалоба Ну и k с каждой итерацией умножается на 10, всё это будет иметь всё те-же перспективы переполнения u64 о которых я говорил в первом посте.... Итого по сути для получения 10 знаков после точки нужно оперировать числами с десятью нулями. И еще в приведенном коде arg = k наверное бомба замедленного действия ибо arg 32бита, а k - 64 :) Надо подумать что будет если arg поступивший на вход функции был близок к максимальному значению 2^32 - 1? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 20 марта, 2015 Опубликовано 20 марта, 2015 · Жалоба И еще в приведенном коде arg = k наверное бомба замедленного действия ибо arg 32бита, а k - 64 :)Именно за счет этого и работает. И переполнения не возникнет. Вы умножили arg на 10. Старшие биты вылезли за пределы 32-битного числа. Вы их выделяете и выводите сдвигом на 32 вправо. Потом присвоили получившийся k обратно 32-битному числу, обрезав те самые выдвинувшиеся за 32 бита (и уже напечатанные) лишние разряды. И цикл повторяется снова. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 20 марта, 2015 Опубликовано 20 марта, 2015 · Жалоба Ну и k с каждой итерацией умножается на 10, всё это будет иметь всё те-же перспективы переполнения u64 о которых я говорил в первом посте....Внимательнее на код посмотрите. Где Вы видите умножение k на 10???? И еще в приведенном коде arg = k наверное бомба замедленного действия ибо arg 32бита, а k - 64 :)И что? Надо подумать что будет если arg поступивший на вход функции был близок к максимальному значению 2^32 - 1?Очевидно первая цифра после '.' будет '9'. B) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 20 марта, 2015 Опубликовано 20 марта, 2015 · Жалоба Именно за счет этого и работает. И переполнения не возникнет. Вы умножили arg на 10. Старшие биты вылезли за пределы 32-битного числа. Вы их выделяете и выводите сдвигом на 32 вправо. Потом присвоили получившийся k обратно 32-битному числу, обрезав те самые выдвинувшиеся за 32 бита (и уже напечатанные) лишние разряды. И цикл повторяется снова. Даа, похоже именно на этом всё и держится, действительно должно работать. А сразу и не сообразишь так сходу ) Внимательнее на код посмотрите. Где Вы видите умножение k на 10???? Сначала исходил из простой логики что если в цикле arg = k k = (u64)arg * 10; То в общем то и arg и k в каждой итерации множаются на 10. Так сходу не очевидно что вы заставили переполнение работать на себя, но Сергей Борщ всё разъяснил. Не знаю, как по мне - рабочий, но слегка запутанный код со спецэффектами.... Безусловно признак хакерского мастерства ))) Жму руку! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
neiver 0 26 марта, 2015 Опубликовано 26 марта, 2015 · Жалоба А у меня статейка по этому поводу есть: http://we.easyelectronics.ru/Soft/preobraz...ey-tochkoy.html Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 26 марта, 2015 Опубликовано 26 марта, 2015 · Жалоба Спасибо, почитаю обязательно! К слову, именно ваша статья про работу с портами на шаблонной магии подтолкнула меня начать вникать в эту самую магию и С++ в целом. Так что даже двойное спасибо! :cheers: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 63 26 марта, 2015 Опубликовано 26 марта, 2015 · Жалоба В общем вычитать что и куда я немного не понял... сделал так: for( uint8_t i = 0; i < fracDigits; i++ ) { T digit = frac * 10 / POW2F; fracBuf[i] = digit + '0'; frac = frac * 10 % POW2F; } На случай, если где-нибудь еще потребуется частное и остаток для одинаковых делимого и делителя: в библиотеке stdlib есть замечательные функции div(), ldiv() и lldiv(). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 26 марта, 2015 Опубликовано 26 марта, 2015 · Жалоба Про эти функции слыхал, но не стал использовать т.к. это всё реализовано в шаблонном методе и тип T меняется от 8 до 32бит в зависимости от формата числа с фиксированной точкой. Можно конечно попробовать для всего использовать самую "длинную" функцию, и может быть даже это будет уже быстрее, не знаю... Потом немного по оптимизирую, тем более статью neiver подбросил, может оттуда какие идеи позаимствую. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться