Есть ли не float альтернатива pow ()?

9

Я просмотрел ССЫЛКУ НА ЯЗЫКЕ на веб-сайте Arduino , и я не могу найти эквивалент, не относящийся к Float, pow() я должен упустить что-то большое, но для жизни я в тупике! Я нашел pow()в столбце FUNCTIONS под заголовком Math (как я и ожидал), но он говорит, что оба параметра, [base] и [exponent] оба (float). И есть только шесть других записей под заголовком Math; ни один из них не кажется целочисленной версией. Все, что я хочу сделать, это сгенерировать степени 2, используя показатели от 0 до 10. Например, 2 ^ 0 = 1, затем 2 ^ 1 = 2, затем 2 ^ 2 = 4, затем 2 ^ 3 = 8, затем 2 ^ 4 = 16, затем 2 ^ 5 = 32, затем 2 ^ 6 = 64, затем 2 ^ 7 = 128, затем 2 ^ 8 = 256, затем 2 ^ 9 = 512, затем 2 ^ 10 - 1024

Является ли использование поплавков единственным способом, которым я могу это сделать? Я начинаю чувствовать, что я не соглашаюсь с реальностью, и фактически посчитал мои лекарства, но я именно там, где и должен быть. Позвольте мне заранее извиниться за этот вопиющий недосмотр, с которым я потратил впустую ваше время, но я просмотрел все 9 страниц тегов и провел поиск, о котором только мог подумать. Я признаю, что я не потратил все ЭТО много времени, но я был уверен, что это будет всего лишь пять минут!

Бенс Кауликс
источник
2
Для общего случая целочисленного pow (), см. Stackoverflow.com/questions/101439/… . Для степеней 2, просто используйте смены.
Питер Кордес

Ответы:

8

В общем случае ответ @dat_ha правильный, но стоит отметить, что вам нужен очень особый случай ... степени двойки. Поскольку компьютеры используют двоичную арифметику, для операций с степенью двойки часто доступны некоторые ярлыки.

Умножение числа на степень два может быть выполнено с помощью операции сдвига влево ( <<), которая буквально сдвигает цифры двоичного представления числа (то есть биты) влево. Во второй базе сдвиг битов на одну позицию влево - это то же самое, что умножение на 2, точно так же, как в базовой 10 сдвиг цифр на одну позицию влево - это умножение на 10. Для полного объяснения оператора сдвига влево в C ++ см. этот ответ на переполнение стека .

Важно отметить, что сдвиг влево может привести к потере информации; биты, сдвинутые с конца, теряются. Поскольку вам нужны полномочия от 2 до 10, вы в безопасности при работе со знаковыми целыми числами, которые имеют максимальное значение в 2^15-1Arduino Uno .

Учитывая эти предостережения, вот функция для вычисления степеней двух в этих ограничениях. Это очень быстрый код, потому что операция левого сдвига является операцией очень низкого уровня, и умножение фактически не выполняется.

int pow2(int p){
    return 1 << p;
}
Джейсон Кларк
источник
Ошибка: он может доходить до 2 ^ 32 - 1, если вы используете unsigned long.
Дата Ха
@DatHa спасибо, я, кажется, потерял слово «подписано» во время редактирования. Исправлена.
Джейсон Кларк
1
Он может пройти мимо 2 ^ 32 - 1, если вы используете реализацию целочисленной арифметики произвольной точности
Dat Han Bag
Я хотел бы, в частности, знать, почему результаты целочисленного преобразования для результатов pow () НЕ работают для степеней 2. Для меня pow (2,3) возвращает 8.00, но в то время как int (8.00) возвращает 8 , int (pow (2,3)) возвращает 7!
KDM
1

Он работает с int, double, longи float. unsigned longи unsigned intдолжен также работать. Вы не обязаны использовать ТОЛЬКО поплавки.

Надеюсь, это помогло!

Дат Ха
источник
Причина, по которой приведенный выше ответ работает, состоит в том, что набор действительных чисел (которые содержат числа с плавающей точкой) содержит набор целых чисел
Dat Han Bag
@DatHanBag: И что еще более важно, каждое 32-битное целое число в точности представлено a double. На самом деле, поскольку плавающая точка IEEE основана на двоичном представлении мантиссы / экспоненты, каждая степень 2 должна быть точно представима даже за пределами 2 ^ 53 (точка, где doubleне может быть представлено любое произвольное целое число, 1 единица в последнем месте мантисса больше 1,0).
Питер Кордес
@PeterCordes Да, я знал это. Возможно, я должен был сказать «ограниченные множества», когда ссылался на наборы с плавающей точкой и целочисленные значения для arduino в своем комментарии об ответе
Dat Han Bag
4
Это несколько верный ответ на общий вопрос об использовании pow()целых чисел, но AFAICT arduino даже не имеет аппаратной плавающей запятой, поэтому это ужасный ответ. Целочисленная pow()реализация, подобная этой, которая выполняется с умножением и сложением времени в log2 (n), скорее всего, будет работать лучше, и если не упомянуть, что сдвиги битов работают для степеней 2, то это просто ужасный ответ на этот вопрос.
Питер Кордес
1
@PeterCordes "так что это ужасный ответ". - согласился, что это своего рода некачественный упрощенный ответ. pow () определенно вычисляется в log2 (n) - простом методе, изученном в школе (умножение числа на степень не так эффективно). Вы можете сделать это лучше с преобразованием Фурье для действительно больших целых чисел - например. Но, возможно, ОП примет и понравится.
Дат Хэн Бэг