빠른 고정점 power, log, expand sqrt
저는 고정 포인트 클래스(10.22)가 있고 파워, sqrt, 확장 기능이 필요합니다.
아, 이 일을 어디서부터 시작해야 할지 모르겠어요.유용한 기사에 대한 링크를 제공하거나 코드를 제공할 수 있는 사람이 있습니까?
exp 기능이 있으면 power와 sqrt를 구현하는 것이 비교적 쉬워진다고 가정합니다.
pow( x, y ) => exp( y * log( x ) )
sqrt( x ) => pow( x, 0.5 )
제 로그 규칙 중 몇 가지를 기억하는 것처럼, 다른 것은 많이 기억나지 않습니다.
아마도 sqrt와 pow에 대한 더 빠른 방법도 있을 것이므로 위에서 설명한 방법을 사용한다고 말해도 그 앞에 있는 어떤 포인터라도 감사할 것입니다.
참고:이것은 크로스 플랫폼이고 순수한 C/C++ 코드여야 하기 때문에 어떤 어셈블러 최적화도 사용할 수 없습니다.
아주 간단한 해결책은 적절한 테이블 기반 근사를 사용하는 것입니다.입력을 올바르게 줄이면 실제로 많은 데이터가 필요하지 않습니다.exp(a)==exp(a/2)*exp(a/2)
, 은 로 만 입니다 이 입니다 은 만 이 로 exp(x)
위해서1 < x < 2
는 ~IIRC로입니다. 이 범위에서 룬가-쿠타 근사치는 ~16개의 항목 IIRC로 합리적인 결과를 제공합니다.
마찬가지로 하게,sqrt(a) == 2 * sqrt(a/4) == sqrt(4*a) / 2
,즉,은블한만다rs합니다에 대한 테이블 항목만 합니다.1 < a < 4
는 좀 더 . (a) 가 log(a) == 1 + log(a/e)
이지만 log는 6 반복을 입니다. 이것은 다소 느린 반복이지만 log(1024)는 6.9에 불과하므로 많은 반복을 하지 않을 것입니다.
pow에 우선"할 수 에 도 " " 합니다 " 을 " 합니다 " " " " " " " " 을).pow(x,y)==pow(x, floor(y)) * pow(x, frac(y))
. 이것은 효과가 있습니다.pow(double, int)
사소합니다(정복하고 정복합니다).
[edit] 의 에 에 의 log(a)
, 테이블을 보관하는 것이 유용할지도 모릅니다.1, e, e^2, e^3, e^4, e^5, e^6, e^7
다를 줄일 수 .log(a) == n + log(a/e^n)
해당 표에서 간단한 하드 코딩된 이진 검색을 통해 검색할 수 있습니다.것은 , 7로 3는만지리은한다을는면yee7euoen는tsym서oe면한3t7st3'로te^n
에 대신에n
마다,e
.
2] [ 2] log(a/e^n)
용어를 사용할 수 있습니다.log(a/e^n) = log((a/e^n)^8)/8
- 각 반복은 3비트를 더 생성합니다.
테이블 검색으로 .그러면 코드와 테이블 크기가 작게 유지됩니다.이것은 일반적으로 임베디드 시스템의 코드이며 대용량 캐시가 없습니다.
[편집 3] 그것은 여전히 내 편에서는 똑똑하지 않습니다.log(a) = log(2) + log(a/2)
값을 . 만 하면 하면 만 .log2=0.6931471805599
0의 , , 0 를 의 , a
테이블에 θ에 고정점 상수 θ θ θ θ θ θ(θ) θ θ(θ)를 .log2
지침만큼 수 . 3개의 지침만큼 낮을 수 있습니다.
을 해서.e
는 " 것"기다을한us기것"erat"penlog(e)=1.0
일정하지만 그것은 잘못된 최적화입니다.0.69314718005599는 1.0만큼 좋은 상수이며, 둘 다 10.22 고정 지점에서 32비트 상수입니다.범위 감소 상수로 2를 사용하면 분할에 비트 시프트를 사용할 수 있습니다.
[edit 5] 그리고 Q10.22에 저장하기 때문에 log(65536)=11.09035488.(16 x log(2))를 더 잘 저장할 수 있습니다."x16"은 정밀도가 4비트 더 있음을 의미합니다.
아직도 편집 2에서 요령을 얻으셨잖아요log(a/2^n) = log((a/2^n)^8)/8
. 기본적으로, 이것은 당신에게 결과를 가져다 줍니다.(a + b/8 + c/64 + d/512) * 0.6931471805599
- [0,7] 범위의 b,c,d.a.bcd
정말로 8진수입니다. 일이 ( 2,4하게 잘 합니다.) 8을로운이다로다잘게도의)2다(잘다게t도이r,s(e8dyes2e6eahe
[편집 4] 아직 끝이 열려 있었습니다.pow(x, frac(y)
정당합니다pow(sqrt(x), 2 * frac(y))
그리고 우리는 괜찮은 사람이 있습니다.1/sqrt(x)
. 그게 훨씬 더 효율적인 접근법이 될 겁니다frac(y)=0.101
즉2 더하기8.2π, π 1/2 π 1/8.그럼 그 말은x^0.101
이다 ㅇ(x^1/2 * x^1/8)
.그렇지만x^1/2
정당합니다sqrt(x)
그리고.x^1/8
이다 ㅇ(sqrt(sqrt(sqrt(x)))
더 수술하면 돼, . 만 하면 하면 만 - NR(x)
우리에게 주는1/sqrt(x)
그래서 우리는 계산합니다.1.0/(NR(x)*NR((NR(NR(x)))
는 최종 결과만 뿐, 직접 . 우리는 최종 결과만 뒤집을 뿐, sqrt 함수를 직접 사용하지는 않습니다.
아래는 Clay S의 C 구현 예입니다.Turner의 고정점 로그 베이스 2 알고리즘[1]알고리즘은 어떤 종류의 룩업 테이블도 요구하지 않습니다.이것은 많은 마이크로컨트롤러의 경우와 같이 메모리 제약이 엄격하고 프로세서에 FPU가 부족한 시스템에서 유용할 수 있습니다.로그 베이스 e 및 로그 베이스 10은 또한 임의의 베이스 n에 대해 다음과 같은 로그 속성을 사용하여 지원됩니다.
logₘ(x)
logₙ(x) = ───────
logₘ(n)
여기서 이 알고리즘의 경우 m은 2입니다.
이 구현의 좋은 특징은 가변 정밀도를 지원한다는 점입니다. 정밀도는 런타임에 범위를 희생시켜 결정할 수 있습니다.제가 구현한 방식으로는 중간 결과를 유지하기 위해 프로세서(또는 컴파일러)가 64비트 수학을 수행할 수 있어야 합니다.64비트 지원이 필요하지 않도록 쉽게 조정할 수 있지만 범위는 줄어들 것입니다.
기능을 는 ① ③ ④ ⑤,x
된 Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ,precision
. 예를 들어 만약precision
그럼 16살이겠네요.x
2^16(65536)에 의해 스케일링되어야 합니다.결과는 입력과 동일한 척도 인자를 갖는 고정점 값입니다.환값값의 INT32_MIN
음의 무한을 나타냅니다.환값값의 INT32_MAX
를은다입니다.errno
됩니다.EINVAL
않음을 , 가 을 을 가
#include <errno.h>
#include <stddef.h>
#include "log2fix.h"
#define INV_LOG2_E_Q1DOT31 UINT64_C(0x58b90bfc) // Inverse log base 2 of e
#define INV_LOG2_10_Q1DOT31 UINT64_C(0x268826a1) // Inverse log base 2 of 10
int32_t log2fix (uint32_t x, size_t precision)
{
int32_t b = 1U << (precision - 1);
int32_t y = 0;
if (precision < 1 || precision > 31) {
errno = EINVAL;
return INT32_MAX; // indicates an error
}
if (x == 0) {
return INT32_MIN; // represents negative infinity
}
while (x < 1U << precision) {
x <<= 1;
y -= 1U << precision;
}
while (x >= 2U << precision) {
x >>= 1;
y += 1U << precision;
}
uint64_t z = x;
for (size_t i = 0; i < precision; i++) {
z = z * z >> precision;
if (z >= 2U << (uint64_t)precision) {
z >>= 1;
y += b;
}
b >>= 1;
}
return y;
}
int32_t logfix (uint32_t x, size_t precision)
{
uint64_t t;
t = log2fix(x, precision) * INV_LOG2_E_Q1DOT31;
return t >> 31;
}
int32_t log10fix (uint32_t x, size_t precision)
{
uint64_t t;
t = log2fix(x, precision) * INV_LOG2_10_Q1DOT31;
return t >> 31;
}
이 구현을 위한 코드는 표준 입력에서 읽은 숫자에서 로그를 계산하고 표시하는 데 이 함수를 사용하는 방법을 보여주는 샘플/테스트 프로그램과 함께 Github에 존재합니다.
[1]C. S. 터너, "빠른 이진 로그 알고리즘", IEEE 신호 처리 Mag., pp. 124, 140, 2010년 9월.
좋은 출발점은 잭 크렌쇼의 책 "실시간 프로그래밍을 위한 수학 툴킷"입니다.다양한 초월 함수에 대한 알고리즘과 구현에 대한 좋은 논의를 가지고 있습니다.
정수 연산만을 사용하여 나의 고정점 sqrt 구현을 확인합니다.발명하는 것이 재미있었습니다.이제 꽤 늙었어요.
그렇지 않으면 코딕 알고리즘 집합을 확인합니다.그것이 당신이 열거한 모든 함수와 삼각 함수를 구현하는 방법입니다.
편집 : 여기 GitHub에 검토한 소스를 게시했습니다.
언급URL : https://stackoverflow.com/questions/4657468/fast-fixed-point-pow-log-exp-and-sqrt
'programing' 카테고리의 다른 글
ASP.net Windows Server 2008 R2 웹 서버에 파일을 업로드하려고 할 때 "Access to the path"(경로 접근 거부)라는 오류가 표시됨 (0) | 2023.09.11 |
---|---|
ASP.net Getting the error "Access to the path is denied." while trying to upload files to my Windows Server 2008 R2 Web server (0) | 2023.09.11 |
N/2번 이상 반복되는 배열의 요소를 찾는 방법은? (0) | 2023.09.11 |
Win32에서 GCC로 어셈블리 기호에 선행 밑줄을 추가하시겠습니까? (0) | 2023.09.11 |
쿠키를이름으로삭제하시겠습니까? (0) | 2023.09.11 |