Przybliżone e^x

Chciałbym przybliżyć e x funkcja.

Czy jest to możliwe przy użyciu podejścia opartego na typach wielu splinów? i. E pomiędzy x1 i x2, then

Y1 = a1x + b1, między x2 i x3,

Then

Y2 = a2x + b2

Etc

To jest dedykowane fpga sprzęt, a nie Procesor ogólnego przeznaczenia. Jako taki sam muszę stworzyć tę funkcję. Dokładność jest znacznie mniej niepokojąca. Ponadto nie mogę sobie pozwolić na więcej niż jeden obwód mnożenia i / lub wiele przesunięć / dodawarek. Chcę też czegoś znacznie mniejszego niż funkcja Kordyliery, w rzeczywistości rozmiar jest krytyczny.

Author: Ian Boyd, 2011-08-08

10 answers

A może taka strategia, która używa wzoru

E x = 2 x / ln(2)

  1. Precalculate 1/ln(2)
  2. pomnóż tę stałą przez twój argument (1 mnożenie)
  3. użyj przesunięć binarnych, aby podnieść 2 do całkowitej części mocy (zakłada format exp+mantissa)
  4. Dopasuj na podstawie ułamkowej mocy 2 reszty (prawdopodobnie drugiego mnożenia)

Zdaję sobie sprawę, że to nie jest kompletne rozwiązanie, ale wymaga tylko jednego mnożenia i redukuje pozostały problem do przybliżenia ułamkowej mocy 2, która powinna być łatwiejsza do zaimplementowania w sprzęcie.

Ponadto, jeśli Twoja aplikacja jest wystarczająco wyspecjalizowana, możesz spróbować ponownie pobrać cały kod numeryczny, który będzie działał na twoim sprzęcie w systemie liczbowym base-e i zaimplementować swój sprzęt zmiennoprzecinkowy do pracy w bazie e . Wtedy nie jest potrzebna żadna konwersja.

 22
Author: Lucas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-15 21:39:06

Jeśli x jest liczbą całkowitą, możesz po prostu mnożyć e przez siebie w kółko.

Jeśli x nie jest liczbą całkowitą, można obliczyć E floor(x) stosując powyższą metodę, a następnie pomnożyć przez mały okres korekty. Ten okres korekty można łatwo obliczyć za pomocą wielu metod przybliżania. Jednym z takich sposobów jest to:

E f1 + f(1 + f/2(1 + f/3(1 + f/4))), gdzie f jest częścią ułamkową x

To pochodzi z (zoptymalizowane) rozszerzenie serii mocy e x, co jest bardzo dokładne dla małych wartości x. Jeśli potrzebujesz większej dokładności, po prostu dopasuj więcej terminów do serii.

To matematyka.pytanie stackexchange zawiera kilka dodatkowych mądrych odpowiedzi.

EDIT: zauważ, że istnieje szybszy sposób obliczania e n nazywany wykładnikiem przez kwadrat.

 12
Author: tskuzzy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 12:19:19

Lub możesz po prostu zrobić pow(M_E, x) W C. (niektóre platformy nie mają zdefiniowanej M_E; na nich być może będziesz musiał ręcznie podać wartość e , która wynosi w przybliżeniu 2.71828182845904523536028747135266249775724709369995.)

(jak zaznacza David w komentarzach, exp(x) byłoby bardziej efektywne niż pow(M_E, x). Znowu, mózg jeszcze się nie włączył.)

Czy masz przypadek użycia, w którym obliczanie e x czy udowodnione wąskie gardło? Jeśli nie, powinieneś najpierw kodować pod kątem czytelności; spróbuj tylko tego rodzaju optymalizacje, jeśli oczywiste podejście jest zbyt wolne.

 2
Author: Jonathan Grynspan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-08 15:41:36

Po pierwsze, co motywuje to przybliżenie? Innymi słowy, co dokładnie jest nie tak z prostym exp(x)?

To powiedziawszy, typową implementacją {[0] } jest

  • Znajdź liczbę całkowitą k i liczbę zmiennoprzecinkową r taką, że x=k*log(2) + r i r wynosi od -0,5 * log (2) do 0,5 * log (2).
  • z tą redukcją, exp(x) jest 2 k*exp(r).
  • obliczenie 2 k jest bardzo proste.
  • standardowe implementacje exp(x) użyj algorytmu Remesa, aby stworzyć wielomian minimax przybliżający exp(r).
  • Możesz zrobić to samo, ale użyj wielomianu zredukowanego rzędu.

Oto kicker: bez względu na to, co zrobisz, szanse są bardzo wysokie, że twoja funkcja będzie znacznie wolniejsza niż zwykłe wywołanie exp(). Większość funkcji exp() jest zaimplementowana w koprocesorze matematycznym komputera. Ponowne wdrożenie tej funkcjonalności w oprogramowaniu, nawet ze zmniejszoną precyzją, będzie rząd wielkości wolniejszy niż tylko użycie exp().

 2
Author: David Hammen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-08 16:33:43

Http://martin.ankerl.com/2007/02/11/optimized-exponential-functions-for-java / zastosowanie metody Schraudolpha (http://nic.schraudolph.org/pubs/Schraudolph99.pdf ) w języku Java:

public static double exp(double val) {
    final long tmp = (long) (1512775 * val) + (1072693248 - 60801);
    return Double.longBitsToDouble(tmp << 32);
}

Oraz https://math.stackexchange.com/a/56064 (poszukaj PADE ' a).

 2
Author: jdbertron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 12:19:15

Jeśli chodzi o sprzęt, mam dla Ciebie świetne rozwiązanie, jeśli potrzebujesz, aby było dokładne na poziomie bitowym. (Inaczej po prostu zrób przybliżenie jak powyżej). Tożsamość to exp (x) = cosh (x) + sinh( x), sinus hiperboliczny i cosinus. Haczyk polega na tym, że hiperboliczny sinus i cosinus można obliczyć za pomocą techniki KORYCZNEJ, a co najlepsze, są one jedną z szybkich funkcji KORYCZNYCH, co oznacza, że wyglądają prawie jak mnożenie zamiast prawie jak dzielenie!

Czyli o obszarze tablicy mnożnik, możesz obliczyć wykładnik z dowolną precyzją w zaledwie 2 cykle!

Poszukaj metody CORDIC - jest niesamowita dla implementacji sprzętowej.

Innym sprzętowym podejściem jest użycie małej tabeli w połączeniu z formułą, o której inni wspominali: exp(x + y) = exp(x) * exp (y). Możesz podzielić liczbę na małe pola bitowe-powiedzmy 4 lub 8 bitów na raz - i po prostu sprawdzić wykładnik dla tego pola bitowego. Prawdopodobnie tylko skuteczne dla wąskich obliczeń, ale to inne podejście.

 2
Author: user2465201,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-29 17:53:13

Wolfram przedstawia kilka dobrych sposobów przybliżenia go w kategoriach szeregowych itp:

Strona Wikipedii na Seria Taylora pokazuje również przykład rozszerzenia e x około 0:

 1
Author: aioobe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-08 14:32:53

Oczywiście, że jest "możliwe". Jest kilka problemów.

  1. Jakie są Twoje wymagania dotyczące dokładności?

  2. Czy jesteś gotów użyć splinów wyższego rzędu?

  3. Ile pamięci chcesz na to wydać? Funkcja liniowa w wystarczająco małych interwałach przybliża funkcję wykładniczą do dowolnego stopnia wymaganej dokładności, ale może wymagać bardzo małego interwału.

Edit:

Biorąc pod uwagę dodatkowe informacje pod warunkiem, przeprowadziłem szybki test. Redukcja zakresu może być zawsze stosowana w funkcji wykładniczej. Tak więc, jeśli chcę obliczyć exp (x)dla dowolnego x, to mogę przepisać problem w postaci...

y = exp(xi + xf) = exp(xi)*exp(xf)

Gdzie xi jest częścią całkowitą x, a xf jest częścią ułamkową. Część całkowita jest prosta. Oblicz xi w postaci binarnej, a następnie powtarzające się kwadratury i mnożenia pozwalają obliczyć exp (xi) w stosunkowo niewielu operacjach. (Inne sztuczki, użycie mocy 2 i innych interwałów może jeszcze dać większa prędkość dla głodnych prędkości.)

Pozostaje tylko obliczyć exp (xf). Czy możemy użyć spline z segmentami liniowymi do obliczenia exp( xf), w przedziale [0,1] z tylko 4 segmentami liniowymi, z dokładnością do 0,005?

To ostatnie pytanie jest rozwiązane przez funkcję, którą napisałem kilka lat temu, która przybliża funkcję z splajnem danej kolejności, do ustalonej tolerancji na maksymalny błąd. Kod ten wymagał 8 segmentów w przedziale [0,1], aby osiągnąć wymagana tolerancja z fragmentaryczną liniową funkcją splajnu. Jeśli zdecyduję się na dalsze zmniejszenie odstępu do [0,0.5], mógłbym teraz osiągnąć zalecaną tolerancję.

Odpowiedź jest prosta. Jeśli chcesz zredukować zakres, aby zmniejszyć X do przedziału [0.0.5], wykonaj odpowiednie obliczenia, to tak, możesz osiągnąć żądaną dokładność za pomocą liniowego splajnu w 4 segmentach.

W końcu, zawsze będzie lepiej używać mocno zakodowanej funkcji wykładniczej chociaż. Wszystkie operacje wymienione powyżej na pewno będą wolniejsze niż te, które dostarczy Twój kompilator, jeśli exp (x) jest dostępny.

 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-08 18:55:54

To nie jest odpowiednie dla niestandardowych FPGA, ale warto wspomnieć.

Http://www.machinedlearnings.com/2011/06/fast-approximate-logarithm-exponential.html

Oraz kod źródłowy:

Https://code.google.com/archive/p/fastapprox/downloads

"szybsza" implementacja składa się tylko z 3 kroków (mnożenie, dodawanie, konwersja float do int) i ostatecznego rzutu z powrotem do float. Z mojego doświadczenia wynika, że jest to dokładność 2%, co może wystarczyć, jeśli nie dbasz o rzeczywistą wartość, ale używają wartości w iteracji maksymalizacji prawdopodobieństwa logowania.

 1
Author: Mark Lakata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-27 23:51:37

To nie jest gładka interpolacja splajnu, o którą prosiłeś, ale jej wydajność obliczeniowa:

float expf_fast(float x) {
   union { float f; int i; } y;
   y.i = (int)(x * 0xB5645F + 0x3F7893F5);
   return (y.f);
}

Wyjście Wykresu obraz

 1
Author: nimig18,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-05 21:15:09