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.
10 answers
A może taka strategia, która używa wzoru
E x = 2 x / ln(2)
- Precalculate
1/ln(2)
- pomnóż tę stałą przez twój argument (1 mnożenie)
- użyj przesunięć binarnych, aby podnieść 2 do całkowitej części mocy (zakłada format exp+mantissa)
- 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.
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 f ≈
1 + 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.
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.
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ą, żex=k*log(2) + r
ir
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ącyexp(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()
.
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).
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.
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:
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.
Jakie są Twoje wymagania dotyczące dokładności?
Czy jesteś gotów użyć splinów wyższego rzędu?
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.
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.
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
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