簡體   English   中英

c中的arsinh(x)函數使用查找表

[英]arsinh(x) function in c using a lookup table

我在 c 中實現了一個函數,它接受一個 double 作為參數並返回該 double 的 arsinh 值。 我正在為我的實現使用查找表來近似我的結果,目前我的誤差為 ±0.005,並且大約涵蓋了從 -1000000 到 1000000 的范圍。 我現在遇到的問題是這個函數需要覆蓋雙精度的整個范圍,但我不知道如何做到這一點,因為雙精度的最大值是 1.7976931348623157E+308。 對於非常大的值,是否有其他方法可以近似 arsinh?

#include <stddef.h>
#include <stdlib.h>
#include <emmintrin.h>
#include <stdint.h>
#include <stdbool.h>

double hashMap(double x) {
    typedef struct {
        int k;
        double v;
    } map;

    map items[] = {
        //increment 0.2
        {0, 0.0}, {1, 0.198690110349}, {2, 0.390035319771}, {3, 0.568824898732}, {4, 0.732668256045}, {5, 0.88137358702}, 
        {6, 1.01597313418}, {7, 1.13798204629}, {8, 1.2489833279}, {9, 1.35044074027}, {10, 1.44363547518}, 
        {11, 1.52966049509}, {12, 1.60943791243}, {13, 1.683743144}, {14, 1.75322890111},  
        //increment 0.5 start: 3
        {15, 1.81844645923},
        {16, 1.96572047165}, {17, 2.09471254726}, 
        {18, 2.20934770862}, {19, 2.31243834127}, 
        {20, 2.4060591253}, {21, 2.49177985264}, 
        {22, 2.5708146781}, {23, 2.64412076106}, 
        {24, 2.71246530518},
        //increment 2 start: 8
        {25, 2.77647228072}, 
        {26, 2.9982229503}, 
        {27, 3.1797854377}, 
        {28, 3.33347758688}, 
        {29, 3.46671103788}, 
        {30, 3.58428965186},
        //increment 4 start: 20
        {31, 3.68950386899},
        {32, 3.87163475639}, 
        {33, 4.02567041587}, 
        {34, 4.15912713463}, 
        {35, 4.27685896446}, 
        {36, 4.38218284807}, 
        {37, 4.4774659217}, 
        {38, 4.56445668076}, 
        {39, 4.64448334194}, 
        {40, 4.71857858115},
        //increment 10 start: 60
        {41, 4.78756117999},
        {42, 4.94169343911},
        //increment 20 start: 80
        {43, 5.07521287545}, 
        {44, 5.29834236561}, 
        {45, 5.480656284}, 
        {46, 5.63480235803}, 
        {47, 5.76833076128}, 
        {48, 5.88611174741}, 
        {49, 5.99147079705},
        //increment 50 start: 200
        {50, 5.99147079705},
        {51, 6.2146120984},
        {52, 6.39693243298},
        {53, 6.55108237585},
        {54, 6.68461329016},
        {55, 6.80239599789},
        //increment 100 start: 500
        {56, 6.90775627898},
        {57, 7.09007753022},
        {56, 7.24422802581},
        {57, 7.37775929885},
        {56, 7.49554225253},
        //increment 200 start: 1000
        {57, 7.60090270954},
        {58, 7.78322418995},
        {59, 7.93737482371},
        {60, 8.07090618644},
        {61, 8.1886892016},
        {62, 8.2940497026},
        {63, 8.1886892016},
        {64, 7.49554225253},
        {65, 8.55641394155},
        {66, 8.63052190861},
        //increment 1000 start: 3000
        {67, 8.69951477599},
        {68, 8.98719683629},
        {69, 9.21034038198},
        {70, 9.39266193571},
        {71, 9.5468126137},
        {72, 9.68034400513},
        {73, 9.79812703996},
        //increment 2000 start: 10000
        {74, 9.90348755504},
        {75, 10.0858091111},
        {76, 10.2399597904},
        {77, 9.90348755504},
        //increment 5000 start: 20000
        {78, 10.5966347337},
        {79, 10.8197782848},
        {80, 11.0020998415},
        {81, 11.1562505212},
        {82, 11.2897819138},
        {83, 11.4075649494},
        //increment 15000 start: 50000
        {84, 11.5129254651},
        {85, 11.7752897295},
        {86, 11.9829290943},
        {87, 12.1547793512},
        //increment 20000 start: 110000
        {88, 12.3013828254},
        {89, 12.46843691},
        {90, 12.6115377536},
        {91, 12.7367008966},
        {92, 12.8479265317},
        // increment 40000 start: 210000
        {93, 12.9480099903},
        // increment 50000 start: 250000
        {94, 13.1223633774},
        // increment 100000 start: 300000
        {95, 13.3046849342},
        {96, 13.5923670067},
        // increment 200000 start: 500000
        {97, 13.815510558},
        {98, 14.1519827946},
        {99, 14.4032972229},
        };

        double m = 0;
        double c = 0;


            if (x <= 0.2) {
                m = items[1].v / 0.2;
                c = items[1].v - m * 0.2;
            } else if (x <= 0.4) {
                m = (items[2].v - items[1].v) / 0.2;
                c = items[1].v - m * 0.2;
            } else if (x <= 0.6) {
                m = (items[3].v - items[2].v) / 0.2;
                c = items[2].v - m * 0.4;
            } else if (x <= 0.8) {
                m = (items[4].v - items[3].v) / 0.2;
                c = items[3].v - m * 0.6;
            } else if (x <= 1.0) {
                m = (items[5].v - items[4].v) / 0.2;
                c = items[4].v - m * 0.8;
            } else if (x <= 1.2) {
                m = (items[6].v - items[5].v) / 0.2;
                c = items[5].v - m * 1.0;
            } else if (x <= 1.4) {
                m = (items[7].v - items[6].v) / 0.2;
                c = items[6].v - m * 1.2;
            } else if (x <= 1.6) {
                m = (items[8].v - items[7].v) / 0.2;
                c = items[7].v - m * 1.4;
            } else if (x <= 1.8) {
                m = (items[9].v - items[8].v) / 0.2;
                c = items[8].v - m * 1.6;
            } else if (x <= 2.0) {
                m = (items[10].v - items[9].v) / 0.2;
                c = items[9].v - m * 1.8;
            } else if (x <= 2.2) {
                m = (items[11].v - items[10].v) / 0.2;
                c = items[10].v - m * 2.0;
            } else if (x <= 2.4) {
                m = (items[12].v - items[11].v) / 0.2;
                c = items[11].v - m * 2.2;
            } else if (x <= 2.6) {
                m = (items[13].v - items[12].v) / 0.2;
                c = items[12].v - m * 2.4;
            } else if (x <= 2.8) {
                m = (items[14].v - items[13].v) / 0.2;
                c = items[13].v - m * 2.6;
            } else if (x <= 3.0) {
                m = (items[15].v - items[14].v) / 0.2;
                c = items[14].v - m * 2.8;
            } else if (x <= 3.5) {
                m = (items[16].v - items[15].v) / 0.5;
                c = items[15].v - m * 3.0;
            } else if (x <= 4.0) {
                m = (items[17].v - items[16].v) / 0.5;
                c = items[16].v - m * 3.5;
            } else if (x <= 4.5) {
                m = (items[18].v - items[17].v) / 0.5;
                c = items[17].v - m * 4.0;
            } else if (x <= 5.0) {
                m = (items[19].v - items[18].v) / 0.5;
                c = items[18].v - m * 4.5;
            } else if (x <= 5.5) {
                m = (items[20].v - items[19].v) / 0.5;
                c = items[19].v - m * 5.0;
            } else if (x <= 6.0) {
                m = (items[21].v - items[20].v) / 0.5;
                c = items[20].v - m * 5.5;
            } else if (x <= 6.5) {
                m = (items[22].v - items[21].v) / 0.5;
                c = items[21].v - m * 6.0;
            } else if (x <= 7.0) {
                m = (items[23].v - items[22].v) / 0.5;
                c = items[22].v - m * 6.5;
            } else if (x <= 7.5) {
                m = (items[24].v - items[23].v) / 0.5;
                c = items[23].v - m * 7.0;
            } else if (x <= 8) {
                m = (items[25].v - items[24].v) / 0.5;
                c = items[24].v - m * 7.5;
            } else if (x <= 10) {
                m = (items[26].v - items[25].v) / 2;
                c = items[25].v - m * 8.0;
            } else if (x <= 12) {
                m = (items[27].v - items[26].v) / 2;
                c = items[26].v - m * 10.0;
            } else if (x <= 14) {
                m = (items[28].v - items[27].v) / 2;
                c = items[27].v - m * 12.0;
            } else if (x <= 16) {
                m = (items[29].v - items[28].v) / 2;
                c = items[28].v - m * 14.0;
            } else if (x <= 18) {
                m = (items[30].v - items[29].v) / 2;
                c = items[29].v - m * 16.0;
            } else if (x <= 20) {
                m = (items[31].v - items[30].v) / 2;
                c = items[30].v - m * 18.0;
            } else if (x <= 24) {
                m = (items[32].v - items[31].v) / 4;
                c = items[31].v - m * 20.0;
            } else if (x <= 28) {
                m = (items[33].v - items[32].v) / 4;
                c = items[32].v - m * 24.0;
            } else if (x <= 32) {
                m = (items[34].v - items[33].v) / 4;
                c = items[33].v - m * 28.0;
            } else if (x <= 36) {
                m = (items[35].v - items[34].v) / 4;
                c = items[34].v - m * 32.0;
            } else if (x <= 40) {
                m = (items[36].v - items[35].v) / 4;
                c = items[35].v - m * 36.0;
            } else if (x <= 44) {
                m = (items[37].v - items[36].v) / 4;
                c = items[36].v - m * 40.0;
            } else if (x <= 48) {
                m = (items[38].v - items[37].v) / 4;
                c = items[37].v - m * 44.0;
            } else if (x <= 52) {
                m = (items[39].v - items[38].v) / 4;
                c = items[38].v - m * 48.0;
            } else if (x <= 56) {
                m = (items[40].v - items[39].v) / 4;
                c = items[39].v - m * 52.0;
            } else if (x <= 60) {
                m = (items[41].v - items[40].v) / 4;
                c = items[40].v - m * 56.0;
            } else if (x <= 70) {
                m = (items[42].v - items[41].v) / 10;
                c = items[41].v - m * 60.0;
            } else if (x <= 80) {
                m = (items[43].v - items[42].v) / 10;
                c = items[42].v - m * 70.0;
            } else if (x <= 100) {
                m = (items[44].v - items[43].v) / 20;
                c = items[43].v - m * 80;
            } else if (x <= 120) {
                m = (items[45].v - items[44].v) / 20;
                c = items[44].v - m * 100;
            } else if (x <= 140) {
                m = (items[46].v - items[45].v) / 20;
                c = items[45].v - m * 120;
            } else if (x <= 160) {
                m = (items[47].v - items[46].v) / 20;
                c = items[46].v - m * 140;
            } else if (x <= 180) {
                m = (items[48].v - items[47].v) / 20;
                c = items[47].v - m * 160;
            } else if (x <= 200) {
                m = (items[49].v - items[48].v) / 20;
                c = items[48].v - m * 180;
            } else if (x <= 250) {
                m = (items[50].v - items[49].v) / 50;
                c = items[49].v - m * 200;
            } else if (x <= 300) {
                m = (items[51].v - items[50].v) / 50;
                c = items[50].v - m * 250;
            } else if (x <= 350) {
                m = (items[52].v - items[51].v) / 50;
                c = items[51].v - m * 300;
            } else if (x <= 400) {
                m = (items[53].v - items[52].v) / 50;
                c = items[52].v - m * 350;
            } else if (x <= 450) {
                m = (items[54].v - items[53].v) / 50;
                c = items[53].v - m * 400;
            } else if (x <= 500) {
                m = (items[55].v - items[54].v) / 50;
                c = items[54].v - m * 450;
            } else if (x <= 600) {
                m = (items[56].v - items[55].v) / 100;
                c = items[55].v - m * 500;
            } else if (x <= 700) {
                m = (items[57].v - items[56].v) / 100;
                c = items[56].v - m * 600;
            } else if (x <= 800) {
                m = (items[58].v - items[57].v) / 100;
                c = items[57].v - m * 700;
            } else if (x <= 900) {
                m = (items[59].v - items[58].v) / 100;
                c = items[58].v - m * 800;
            } else if (x <= 1000) {
                m = (items[60].v - items[59].v) / 100;
                c = items[59].v - m * 900;
            } else if (x <= 1200) {
                m = (items[61].v - items[60].v) / 200;
                c = items[60].v - m * 1000;
            } else if (x <= 1400) {
                m = (items[62].v - items[61].v) / 200;
                c = items[61].v - m * 1200;
            } else if (x <= 1600) {
                m = (items[63].v - items[62].v) / 200;
                c = items[62].v - m * 1400;
            } else if (x <= 1800) {
                m = (items[64].v - items[63].v) / 200;
                c = items[63].v - m * 1600;
            } else if (x <= 2000) {
                m = (items[65].v - items[64].v) / 200;
                c = items[64].v - m * 1800;
            } else if (x <= 2200) {
                m = (items[66].v - items[65].v) / 200;
                c = items[65].v - m * 2000;
            } else if (x <= 2400) {
                m = (items[67].v - items[66].v) / 200;
                c = items[66].v - m * 2200;
            } else if (x <= 2600) {
                m = (items[68].v - items[67].v) / 200;
                c = items[67].v - m * 2400;
            } else if (x <= 2800) {
                m = (items[69].v - items[68].v) / 200;
                c = items[68].v - m * 2600;
            } else if (x <= 3000) {
                m = (items[70].v - items[69].v) / 200;
                c = items[69].v - m * 2800;
            }
    return m*x + c;
    }


double approxArsinh_lookup(double x) {

    bool neg = false;

    if (x < 0) {
        x = abs(x);
        neg = true;
    }

    if (neg) return -hashMap(x);
    return hashMap(x);
}

int main() {
    printf("%f\n", approxArsinh_lookup(0));
    return 0;
}

因為這里是arsinh函數的圖表。 在此處輸入圖像描述

從圖中可以假設,當輸入大於某個值時,我們可以使用外部近似方法(使用最后一個元素的 m、c)來計算非常大的值,而不會影響准確性。 如果您想獲得更好的准確度,您可以嘗試找到為您提供足夠准確度的最大值。

對我來說,我會讓表格有點不同,以使代碼更短。 假設稍微改變結構:

typedef struct {
    double min;
    double v;
} map;

然后在實現中,您可以執行如下循環:

    double m = 0;
    double c = 0;
    int i;
    
    for (i = 1; i < MAX_ARRAY_SIZE; i++;) // skip the first value which is 0
    {
        if ((x < items[i].min) && ( x > items[i-1].min))
        {
            m = (items[i].v - items[i-1].v) / (items[i].min - items[i-1].min);
            c = items[i].v - m * items[i].min;
            break;
        }
    }
    if (i == MAX_ARRAY_SIZE) // input value is greater than array size
    {
        m = (items[MAX_ARRAY_SIZE - 1].v - items[MAX_ARRAY_SIZE - 2].v) / (items[MAX_ARRAY_SIZE - 1].min - items[MAX_ARRAY_SIZE - 2].min);
        c = items[MAX_ARRAY_SIZE - 1].v - m * items[MAX_ARRAY_SIZE - 1].min;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM