Czy istnieje nie-zmiennoprzecinkowa alternatywa dla pow ()?

9

Przeszukałem REFERENCJĘ JĘZYKOWĄ na stronie internetowej Arduino i nie mogę znaleźć odpowiednika innego niż Float. pow() Muszę przegapić coś dużego, ale dla mojego życia jestem zakłopotany! Znalazłem pow()w kolumnie FUNKCJE pod nagłówkiem Math (jak bym się spodziewał), ale mówi, że oba parametry, [baza] i [wykładnik] są oba (zmiennoprzecinkowe). I jest tylko sześć innych pozycji pod nagłówkiem Math; żadna z nich nie wydaje się być wersją całkowitą. Wszystko, co chcę zrobić, to wygenerować potęgę 2 za pomocą wykładników od 0 do 10. Jak 2 ^ 0 = 1, a następnie 2 ^ 1 = 2, a następnie 2 ^ 2 = 4, a następnie 2 ^ 3 = 8, a następnie 2 ^ 4 = 16, a następnie 2 ^ 5 = 32 następnie 2 ^ 6 = 64 następnie 2 ^ 7 = 128 następnie 2 ^ 8 = 256 następnie 2 ^ 9 = 512, a następnie 2 ^ 10 to 1024

Czy używanie pływaków jest jedynym sposobem, w jaki mogę to zrobić? Zaczynam czuć się jak w sprzeczności z rzeczywistością i faktycznie policzyłem moje leki, ale jestem dokładnie tam, gdzie powinienem być. Przepraszam z góry za ten okropny nadzór, nad którym zmarnowałem twój czas, ale przejrzałem wszystkie 9 stron tagów i przeprowadziłem wyszukiwanie, o którym mogłem pomyśleć. Przyznaję, że nie spędziłem tak dużo czasu, ale byłem pewien, że to będzie tylko pięć minut!

Bence Kaulics
źródło
2
Ogólny przypadek liczby całkowitej pow () znajduje się na stackoverflow.com/questions/101439/… . Aby uzyskać moc 2, po prostu użyj zmiany.
Peter Cordes

Odpowiedzi:

8

W ogólnym przypadku odpowiedź @dat_ha jest poprawna, ale warto zauważyć, że chcesz bardzo szczególnego przypadku ... potęgi dwóch. Ponieważ komputery używają arytmetyki binarnej, operacje obejmujące potęgi dwóch często mają dostępne skróty.

Mnożenie liczby przez potęgę dwóch można osiągnąć za pomocą operacji przesunięcia w lewo ( <<), która dosłownie przesuwa cyfry binarnej reprezentacji liczby (tj. Bitów) w lewo. W bazie drugiej przesunięcie bitów o jedno miejsce w lewo jest takie samo jak pomnożenie przez 2, tak samo jak w bazie 10 przesunięcie cyfr o jedno miejsce w lewo jest takie samo jak pomnożenie przez 10. Dla pełnego wyjaśnienia operatora lewej zmiany w C ++ zobacz tę odpowiedź na temat przepełnienia stosu .

Należy zauważyć, że przesunięcie w lewo może spowodować utratę informacji; bity odsunięte od końca są tracone. Ponieważ potrzebujesz mocy od 2 do 10, jesteś bezpieczny podczas pracy z podpisanymi liczbami całkowitymi, które mają maksymalną wartość 2^15-1na Arduino Uno .

Biorąc pod uwagę te zastrzeżenia, oto funkcja do obliczania potęg dwóch w ramach tych ograniczeń. Jest to bardzo szybki kod, ponieważ operacja przesunięcia w lewo jest operacją bardzo niskiego poziomu i faktycznie nie jest wykonywane mnożenie.

int pow2(int p){
    return 1 << p;
}
Jason Clark
źródło
Błąd: może wzrosnąć do 2 ^ 32-1, jeśli używasz unsigned long.
Dat Ha
@DatHa dzięki, wydawało mi się, że straciłem słowo „podpis” podczas edycji. Naprawiony.
Jason Clark,
1
Może on przekroczyć 2 ^ 32 - 1, jeśli użyjesz implementacji arytmetyki liczb całkowitych o dowolnej precyzji
Dat Han Bag
Chciałbym szczególnie wiedzieć, dlaczego wyniki konwersji liczb całkowitych na wyniki pow () NIE działają dla potęg 2. 2. Dla mnie pow (2,3) zwraca 8,00, a podczas gdy int (8,00) zwraca 8 , int (pow (2,3)) zwraca 7!
KDM
1

Współpracuje z int, double, longi float. unsigned longi unsigned intpowinien również działać. Nie musisz używać TYLKO pływaków.

Mam nadzieję, że to pomogło!

Dat Ha
źródło
Powodem, dla którego powyższa odpowiedź działa, jest to, że zbiór liczb rzeczywistych (które zawierają liczby zmiennoprzecinkowe) zawiera zbiór liczb całkowitych
Dat Han Bag
@DatHanBag: A co ważniejsze, każda 32-bitowa liczba całkowita jest dokładnie reprezentowana przez double. W rzeczywistości, ponieważ zmiennoprzecinkowy IEEE opiera się na binarnej reprezentacji mantysy / wykładnika, każda potęga 2 powinna być dokładnie reprezentowana nawet powyżej 2 ^ 53 (punkt, w którym doublenie może reprezentować każdej dowolnej liczby całkowitej, 1 jednostki w ostatnim miejscu mantysa jest większa niż 1,0).
Peter Cordes
@PeterCordes Tak, wiedziałem o tym. Może powinienem był powiedzieć „zbiory ograniczone”, odnosząc się do zbiorów zmiennoprzecinkowych i całkowitych dla arduino w moim komentarzu do odpowiedzi
Dat Han Bag
4
Jest to dość poprawna odpowiedź na ogólne pytanie dotyczące używania pow()liczb całkowitych, ale arduino AFAICT nawet nie ma zmiennoprzecinkowego sprzętu, więc jest to straszna odpowiedź. pow()Implementacja liczb całkowitych takich jak ta, która działa w czasie log2 (n) mnożenia i dodawania w celu skumulowania wyniku, prawie na pewno prawdopodobnie działałaby lepiej, a nie wspominając, że przesunięcia bitów działają dla potęg 2, to po prostu okropna odpowiedź na to pytanie.
Peter Cordes,
1
@PeterCordes „więc to okropna odpowiedź”. - zgodził się, że jest to rodzaj uproszczonej odpowiedzi niskiej jakości. pow () jest z pewnością obliczalne w log2 (n) - prostej metodzie nauczonej w szkole (samo pomnożenie liczby do potęgi nie jest tak wydajne). Możesz to zrobić lepiej z transformacją Fouriera dla naprawdę dużych liczb całkowitych - na przykład. Ale może OP to zaakceptuje i polubi.
Dat Han Bag