Всем привет!
Представьте себе 32-битный регистр. Мне нужно использовать этот регистр для математических вычислений. Для этого в него пишем необходимое значение и производим математические действия.
К примеру, мне нужно вписать в этот регистр число 632,626
Есть два выхода:
1) интерпретировать этот регистр, как беззнаковое целое число, с ценой одного разряда равной 0,001 (10^-3) Т.е. записать в регистр число 632,626/0,001 = 632626 = 0x0009A732.
2) интерпретировать этот регистр, как число фиксированной запятой, с ценой одного разряда равной 0,0009765625 (2 ^ -10) = 1/65536 Т.е. записать в регистр число 632,626/(2^-10) = 647809,024 =~ 647809 = 0x0009E281
так вот вопрос : что лучше использовать?
хочу послушать мнения.
По мне, 1/2^10=1/1024=0,0009765625. По вопросу - я бы выбрал первый вариант. Главное, правильный порядок выполнения операций, чтобы не было потери значимости и переполнения.
За статью по представлению чисел спасибо, но ничего нового для себя я из нее не извлек. Понятно, что вещественные числа можно представоять в разных форматах, в том числе в виде числас плавающей и фиксированной запятой. Но вопрос был не о том как можно, а как лучше, узнать мнения остальных.
Целевая платформа ARM cortex m3, 32 бита. Имеет аппаратные делитель и умножитель, но не имеет FPU.
(2^ -10) конечно же равно 1/1024, ошибся, не перепроверил.
Я пока тоже склоняюсь к первому варианту, привычнее как то....
Ща спою... Некоторые моменты (по памяти и по логике вещей).
Два способа: с "десятичным" и "двоичным" весом младшего разряда.
При наличии FPU, по скорости разница будет не очень велика между этими способами.
По точности в ходе операций - зависит от способа представления и того, как реализовать операции. Так как при реализации "в лоб" потенциально неизбежна потеря точности с одной стороны и переполнение с другой.
Если вам нужны только операции сложения и вычитания, то тут всё просто в обеих случаях.
Если требуется умножение, то чуть сложнее.
При умножении надо будет поделить результат, чтобы сдвинуть точку.
Например (с отбрасыванием дробной части).
25,364 * 7,659 = 194,262
(25364 * 7659) / 1000 = 194262
Конкретно в этом примере требуется деление на 1000.
В случае с "двоичным" представлением это сводится к простому сдвигу.
Про деление на память не расскажу - давно это было. Добавил спустя пару минут: Если моё смутное воспоминание меня не подводит, то деление обратно делается.
25,364 * 7,659 * 3,311
25364 * 1000 / 7659 = 3311 Деление Умножение или сдвиг - аналогично.
Для "десятичного" варианта проще преобразование в человеко читаемый вид - itoa, printf("%d") и т.д. с вставкой точки в нужное место.
Для "двоичного" нужен соответствующий алгоритм. Например, сначала привести к "десятичному" варианту с требуемой точностью...
Последний раз редактировалось Kavka Чт апр 03, 2014 11:41:00, всего редактировалось 1 раз.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
ploop писал(а):Второй вариант, кажется, будет точнее при различных математических операциях.
кажется или точнее? как по мне, точность зависит от самого числа, кратно оно "цене деления" в текущем представлении или нет. (0.001 и 0,0009765625 в первом и втором случаях соответственно)
HHIMERA писал(а):Честно... не понимаю причин... или что-то недоговаривается...
не понимаете причин, почему я склоняюсь к первому варианту? Если да, то все просто: я никогда не работал с фиксированной точкой)
Kavka писал(а):Для "десятичного" варианта проще преобразование в человеко читаемый вид - itoa, printf("%d") и т.д. с вставкой точки в нужное место.
Для "двоичного" нужен соответствующий алгоритм. Например, сначала привести к "десятичному" варианту с требуемой точностью...
Именно!) Отличный вывод! Мне нужно чаще вычисления, чем вывод на человеко-читаемый терминал ( ). Вычисления должны быть по возможности быстрые. Сдвиг на ARM выполняется одной командой, поэтому второй вариант выгоднее в плане времени выполнения. Спасибо, Kavka)
Всем спасибо!
Я бы отталкивался от того, насколько критична точность, а про это не сказано, кажется, ни слова.
Чтобы, скажем, при операции 0,998 + 0,001 не получить на выходе 1,000.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Да, про точность я и не писал.
Очень сильно зависит от задачи, от потребностей, конкретного алгоритма.
Это в ведении автора вопроса. Ему и решать.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
когда -то на програмистском форуме слышал крик души - никогда не используйте для денежных расчетов (рубли - копейки ) float...
Потом работал на атс и выдавал данные с базы в бюстгальтерию по расчетам с клиентами - сам убедился - лучше не стОит.
urry, это только подтверждает то, что конкретное представление чисел с ограниченной точностью (фикс. точка) сильно зависит от задачи.
С копейками - это да, наверное, самый яркий пример. Кто это "прочувствовал" на практике - понимают.
Т.е. с копейками надо, как раз, обеспечить жёсткую, фиксированную точность. Чтобы ни при каких обстоятельствах не было 1.259998 руб, а было всегда 1.26 руб. А то может из-за таких "9998" в итоге недобор случиться. Т.е. в реале А+Б=В, а на компе может получиться А+Б меньше B. И чем больше операций с неточными представлениями чисел (типа с 9-ми в конце) тем больше будет разница. Тут нужен "десятичный" вариант представления.
В случае же, например, с каким нибудь PID регулятором - такие ситуации побоку. Там просто нужна достаточная точность, чтобы хватало для устойчивых вычислений. Соответственно, для PID и "двоичный" вариант подойдёт.
Да, и не забывайте, что не всегда можно сравнивать дробные числа на равенство. Особенно в "двоичном" варианте. Желательно сравнивать с диапазоном (плюс-минус эпсилон). На величину младшего разряда или больше. Опять же, сильно зависит от конкретного случая.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
О существовании этих способов округления надо знать и использовать их во всех операциях относящихся к делу.
К тому же "денежные" округления, как правило, компилятором не делаются и их надо ручками в программе делать.
Ну, может быть, foxpro или им подобные с явной спецификой под такие операции и делают это автоматом.
А многие только столкнувшись с этим на практике понимают с чем имеют дело.
Так что, если вот это
HHIMERA писал(а):Сколько там видов округлениия... ась??? Там только банковских несколько...
рассматривать как призыв включить мозги и подумать, то я только за.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Kavka писал(а):
С копейками - это да, наверное, самый яркий пример. Кто это "прочувствовал" на практике - понимают.
Есть байка : американский программер доли цента, которые при расчетах отбрасываются, переводил себе на счет. Пока посадили, нехило накапало.
А вообще вопрос ТС из серии : "Что лучше - шашлык по-карски или трактор "Беларус" ?" Точность, быстродействие, диапазон возможных величин и т.д. и пр. - смотря по обстоятельствам. Один мой знакомец делал 3-байтовую плавучку : один байт - знак и порядок, 2 байта - мантисса. Ему хватало... Сишную арифметику обставлял по скорострельности раза в 4.