programing

빠른 고정점 power, log, expand sqrt

oldcodes 2023. 9. 11. 22:13
반응형

빠른 고정점 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.69314718055990의 , , 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살이겠네요.x2^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 구현을 확인합니다.발명하는 것이 재미있었습니다.이제 꽤 늙었어요.

https://groups.google.com/forum/ ?hl=fr%05aacf5997b615c37&from groups#!topic/comp.lang.c/IpwKbw0MAxw/discussion

그렇지 않으면 코딕 알고리즘 집합을 확인합니다.그것이 당신이 열거한 모든 함수와 삼각 함수를 구현하는 방법입니다.

편집 : 여기 GitHub에 검토한 소스를 게시했습니다.

언급URL : https://stackoverflow.com/questions/4657468/fast-fixed-point-pow-log-exp-and-sqrt

반응형