Поскольку double и float представляют один и тот же тип данных (обычно), что предпочтительнее?
Похоже, что на платах на базе ATMega float
и double
эквивалентны 32-битным (4-байтным) типам данных.
Однако на Arduino Due double
являются 64-битными (8-байтовыми), а float
— 32-битными (4-байтовыми), как и в ATMega.
Я также видел один источник на avr-gcc, в котором double
указан как нестандартный.
Итак, при написании кода для плат на базе ATMega float
предпочтительнее использовать double
, поскольку это сделало бы код эквивалентным для плат Due? Или по какой-то причине двойные
предпочтительнее?
@Ehryk, 👍2
Обсуждение2 ответа
См. avr-gcc
Отклонения от стандарта
двойной
double имеет ширину всего 32 бита и реализован так же, как float
при написании кода для плат на базе ATMega...
Поэтому они одинаковы.
(отредактировано для добавления)
При написании кода предпочтительнее ли использовать одно, а не другое?
Я не очень понимаю ваш вопрос. Вы спрашивали о написании кода для плат на базе ATMega. Вы действительно имеете в виду, если вы пишете код для Due? Быстрый ответ: на Due двойной занимает вдвое больше оперативной памяти, однако он более чем в два раза точнее — около 7,2 десятичных разряда для числа с плавающей запятой по сравнению с 15,9 для двойного числа. (Я не уверен насчет скорости, вероятно, удвоение было бы медленнее, если только оно не реализовано в оборудовании с плавающей запятой, однако я не вижу никаких ссылок на это в техническом описании AT91SAM3X8E).
См.: https://en.wikipedia.org/wiki/Floating_point
Если вам нужна большая точность (однако более медленная и занимающая больше оперативной памяти), вы можете использовать double
, что не будет иметь никакого значения для плат на базе ATmega, но будет иметь значение для Due.
Как сказал Эдгар Боне:
Я бы использовал число с плавающей запятой, чтобы любой, кто читает мой код и может не знать о нестандартном двойнике AVR, знал, какой точности ожидать.
В этом есть смысл.
Предупреждаю вас, что "предпочтительнее" субъективно. Это близко к вопросу "что лучше"? На что ответ: "лучше всего для чего?"
На платах ATMega да, они одинаковые. Если вы затем перенесете код на Arduino Due, они больше не будут одинаковыми при использовании double
, но будут одинаковыми при использовании float
. При написании кода предпочтительнее ли использовать один над другим? Почему или почему нет?, @Ehryk
См. измененный ответ., @Nick Gammon
Ну, строго говоря, сейчас я ориентируюсь только на архитектуры ATMega, я _думал_, что пишу код, который будет одинаковым для всех Arduino. Я не спрашивал, какой из них _лучший_, хотя я думаю, что отвечаю на свой вопрос тем, что float
более известен, лучше описывает тип данных для разных архитектур и совместим с большим количеством Arduino., @Ehryk
Было бы больше смысла, если бы я добавил: «При написании кода Arduino _для неизвестной платы_ предпочтительнее ли использовать один над другим?», @Ehryk
Я полагаю. \*пожал плечами\* - при работе с платами, которые могут иметь ограниченные объемы ОЗУ и флэш-памяти, не всегда возможно кодировать в общем виде., @Nick Gammon
В начале программирования для Arduino я думал, что они, по крайней мере, пытаются сделать код как можно более аппаратно-независимым. В этом духе я думаю, что с этого момента я буду использовать поплавки
., @Ehryk
Этот ответ больше не актуален с avr-gcc, который поддерживает 64-битное двойное (и длинное двойное) начиная с v10. См., например, вики-страницу avr-gcc, на которую вы ссылаетесь., @emacs drives me nuts
@emacsdrivesmenuts Ну да, но с использованием параметра конфигурации, а не по умолчанию. `В avr-gcc v10 и более поздних версиях формат double и long double определяется параметрами конфигурации --with-double= и --with-long-double= соответственно. занимает больше времени, поэтому вашему приложению нужно будет выбирать точность, а не скорость., @Nick Gammon
И возьмите больше памяти, которую вы, возможно, не захотите брать на процессор с ограниченным объемом оперативной памяти., @Nick Gammon
@Nick Gammon: Конечно, речь идет о точности, которая не была целью моего комментария. Кроме того, avr-gcc v10+ поддерживает -mdouble=64
. Единственная причина, по которой по умолчанию установлено значение 32 бита, заключалась в согласовании со старыми (не соответствующими стандарту) версиями avr-gcc., @emacs drives me nuts
Ни один из них не является предпочтительным.
Если в вашем микроконтроллере нет аппаратного модуля с плавающей запятой, использование float или double приводит к огромным накладным расходам для вашей программы.
Поэтому по возможности используйте целочисленную математику.
Вместо того, чтобы работать в вольтах, используйте, например, милливольты.
Однако, если ваш MCU имеет FPU, а некоторые современные более мощные устройства имеют его, вам следует использовать размер float или double, который является родным для FPU. Если это 32-битный FPU, используйте float. Если это 64-битный FPU, вы можете использовать double.
есть ли у вас фактические ориентиры "огромных накладных расходов"? менее эффективно, конечно, но у меня никогда не было проблем с использованием плавающей запятой на Arduino., @BrettAM
в; недействительная установка () { а = 1; } void loop() { a = a * 2; }
использует 482 байта. Измените int
на float
, он почти не удваивается до 878 байт. Еще хуже, если вы измените «2» на «2.0», в то время как это «int» — вы получите 1086 байт. Массивное увеличение. И это не говоря уже о том, сколько времени нужно для запуска. Я сделаю грубый тест., @Majenko
Умножение 1 на 2, пока оно не превысит 32768 (1, 2, 4, 8, 16 и т. д.) с помощью int
, занимает 12 микросекунд. При использовании float это занимает 148 микросекунд. Это более чем в десять раз дольше для одной простой операции., @Majenko
Интересно, что умножение целого числа на «2.0» занимает еще больше времени — 208 микросекунд. в 17 раз дольше., @Majenko
Фиксированная точка требует больше операций, чем просто целочисленное умножение, и мы должны сравнивать 32-битные значения с обеих сторон. в тесте float (a*b)
и long (a*b/1000)
, как было бы в случае, если бы вы выполняли операции в мВ, с плавающей запятой быстрее. Это не вычисление дополнительного старшего байта, необходимого для реальной фиксированной точки, тогда снова фиксированная точка выиграет от более простого делителя. Сложение, безусловно, останется быстрее в фиксированной точке. Я не думаю, что плавающие и фиксированные значения так же очевидны, как это делает сообщество Arduino SE., @BrettAM
@BrettAM: при работе с фиксированной точкой вы никогда не будете масштабироваться на 1000, всегда на степень двойки. И нет, вы не должны сравнивать 32 бита: вы должны сравнивать 32-битные числа с плавающей запятой с фиксированной запятой наименьшего размера, достаточно точного для задания, которое часто будет 16 бит, а иногда даже 8. Я сделал 16-битная реализация функций cos() и sin() с фиксированной точкой, которая в 15,7 раз быстрее, чем стандартные функции <math.h>
., @Edgar Bonet
@EdgarBonet Я упомянул, что делитель плохой, он взят из ответа, который это предложил. Умножение 6,10 с фиксированной точкой дает результат 12,20 (32 бита); поэтому, если их числа не соответствуют 8, умножение должно выполняться в 32 бита. Накладные расходы на написание пользовательской фиксированной точки cos()
(или даже на ее загрузку) намного больше, чем наличие нескольких медленных триггерных функций для большинства приложений здесь, на arduino SE., @BrettAM
@BrettAM: ответ не предлагал деления, он предлагал использовать милливольты, что не одно и то же. Обычно вы должны либо analogRead(pin) * 39U >> 3
, либо analogRead(pin) * 1250UL >> 8
, в зависимости от требуемой точности. И вам не нужно умножать на 32 бита: вы можете сделать умножение 16×16→16 в ассемблере или использовать типы данных _Fract
или _Accum
. Но тогда я согласен с тем, что во многих проектах достаточно циклов процессора, чтобы сделать фиксированную точку неактуальной., @Edgar Bonet
- Преобразование int или float в массив байтов в ардуино
- Почему я получаю разные результаты при компиляции одного и того же кода с разными ide?
- устаревшее преобразование из строковой константы в 'char*'
- Какие есть другие IDE для Arduino?
- Esp8266 Vin контакт
- Будет ли бесконечный цикл внутри loop() работать быстрее?
- Ошибка Cast from 'char*' to 'uint8_t {aka unsigned char}' loses precision [-fpermissive]
- Будет ли .ino-скетч ардуино компилироваться непосредственно на GCC-AVR?
Я бы использовал
float
, чтобы любой, кто читает мой код, кто может не знать о нестандартномдвойнике
AVR, знал, какую точность ожидать. Но это скорее личное предпочтение, чем жесткое правило (поэтому я не считаю его «настоящим» ответом)., @Edgar BonetЯ думаю, что это довольно серьезное рассуждение; можно не ожидать, что «двойник» действительно будет поплавком, если он приходит с другой платформы., @Ehryk