仅使用整数数学对 C 中的正弦信号进行形状修改

Shape modification of sine signal in C using only integer math

我想在 ARM Cortex M0 微控制器上生成一个正弦信号,该微控制器可以通过形状参数 n 对其形状进行自定义。以下面的图为例。在这里,我使用函数

对不同的曲线进行建模
$y(x) = (1/2*(1 + sin(x)))^n$

对于更高的 n,最大值是 "shorter",最小值是“wider”。对于较小的 n,最大值是“wider”,最小值是“shorter”。

为了减少内存消耗和提高性能,我只使用整数数学来生成正弦信号。

下面是正弦计算的代码:

Input range [0R 2πR] mapped to [0 to 1024].

输出范围 [-1.0 1.0] 映射到 [-16,384 16,384].

int_fast16_t sin_bam(int angle_bam) {
  angle_bam %= 1024;
  if (angle_bam < 0)
    angle_bam += 1024;
  uint_fast16_t sub_angle = angle_bam % (1024u / 2);
  int_fast16_t sn = unsigned_mult16x16_into_32(sub_angle, (1024/2 - sub_angle)) / 4;
  if (angle_bam & 512) {
    sn = -sn;
  }
  return sn;
}

有没有人知道如何只用整数数学来实现这样的形状修改?

这个怎么样:

/*
 * Generate integers to drive an n-bit D/A to make a modified sine wave.
 *
 * y = (1/2 * (1 + sin(theta))) ^ q
 *
 * y and q are 16-bit fixed-point numbers:
 *
 * 1000.000000000000 -> -8.000000000000
 *      ...
 * 1111.111111111110 -> -0.000488281250
 * 1111.111111111111 -> -0.000244140625
 * 0000.000000000000 ->  0.000000000000
 * 0000.000000000001 ->  0.000244140625
 * 0000.000000000010 ->  0.000488281250
 *      ...
 * 0111.111111111111 ->  7.999755859375
 *
 * theta is an 8-bit integer where
 *  0x00 -> 0
 *  0xff -> pi
 */
#include <iostream>
#include <string>
using namespace std;
#include <sys/types.h>
#include <stdlib.h>
#include <math.h>

string
fp2str( uint16_t n )
{
    char     buf[64];
    bool     neg = ((n & 0x8000) != 0);

    if (neg) {
        n = ~n + 1;
        buf[0] = '-';
    }

    sprintf( buf + 1, "%14.12f", double(n) / double(0x1000) );

    return neg ? buf : buf + 1;
}

uint16_t fpsin( uint16_t theta ) {  // 0 < theta < 1024 ==> 0 to 2pi
    static uint16_t sintbl[256] = {
        0x0000,0x0019,0x0032,0x004c,0x0065,0x007e,0x0097,0x00b1,0x00ca,0x00e3,0x00fc,0x0115,0x012e,0x0148,0x0161,0x017a,
        0x0193,0x01ac,0x01c5,0x01de,0x01f7,0x0210,0x0229,0x0242,0x025b,0x0274,0x028d,0x02a6,0x02bf,0x02d8,0x02f1,0x0309,
        0x0322,0x033b,0x0354,0x036c,0x0385,0x039d,0x03b6,0x03cf,0x03e7,0x0400,0x0418,0x0430,0x0449,0x0461,0x0479,0x0491,
        0x04aa,0x04c2,0x04da,0x04f2,0x050a,0x0522,0x053a,0x0551,0x0569,0x0581,0x0598,0x05b0,0x05c8,0x05df,0x05f7,0x060e,
        0x0625,0x063d,0x0654,0x066b,0x0682,0x0699,0x06b0,0x06c7,0x06de,0x06f4,0x070b,0x0722,0x0738,0x074f,0x0765,0x077c,
        0x0792,0x07a8,0x07be,0x07d4,0x07ea,0x0800,0x0816,0x082c,0x0841,0x0857,0x086c,0x0882,0x0897,0x08ac,0x08c1,0x08d6,
        0x08eb,0x0900,0x0915,0x092a,0x093f,0x0953,0x0968,0x097c,0x0990,0x09a4,0x09b8,0x09cc,0x09e0,0x09f4,0x0a08,0x0a1b,
        0x0a2f,0x0a42,0x0a56,0x0a69,0x0a7c,0x0a8f,0x0aa2,0x0ab5,0x0ac7,0x0ada,0x0aed,0x0aff,0x0b11,0x0b23,0x0b35,0x0b47,
        0x0b59,0x0b6b,0x0b7d,0x0b8e,0x0b9f,0x0bb1,0x0bc2,0x0bd3,0x0be4,0x0bf5,0x0c05,0x0c16,0x0c27,0x0c37,0x0c47,0x0c57,
        0x0c67,0x0c77,0x0c87,0x0c97,0x0ca6,0x0cb5,0x0cc5,0x0cd4,0x0ce3,0x0cf2,0x0d01,0x0d0f,0x0d1e,0x0d2c,0x0d3a,0x0d48,
        0x0d56,0x0d64,0x0d72,0x0d80,0x0d8d,0x0d9a,0x0da8,0x0db5,0x0dc2,0x0dcf,0x0ddb,0x0de8,0x0df4,0x0e00,0x0e0d,0x0e19,
        0x0e24,0x0e30,0x0e3c,0x0e47,0x0e53,0x0e5e,0x0e69,0x0e74,0x0e7e,0x0e89,0x0e94,0x0e9e,0x0ea8,0x0eb2,0x0ebc,0x0ec6,
        0x0ecf,0x0ed9,0x0ee2,0x0eeb,0x0ef4,0x0efd,0x0f06,0x0f0f,0x0f17,0x0f1f,0x0f28,0x0f30,0x0f38,0x0f3f,0x0f47,0x0f4e,
        0x0f56,0x0f5d,0x0f64,0x0f6a,0x0f71,0x0f78,0x0f7e,0x0f84,0x0f8a,0x0f90,0x0f96,0x0f9c,0x0fa1,0x0fa6,0x0fac,0x0fb1,
        0x0fb6,0x0fba,0x0fbf,0x0fc3,0x0fc7,0x0fcc,0x0fd0,0x0fd3,0x0fd7,0x0fda,0x0fde,0x0fe1,0x0fe4,0x0fe7,0x0fea,0x0fec,
        0x0fef,0x0ff1,0x0ff3,0x0ff5,0x0ff7,0x0ff8,0x0ffa,0x0ffb,0x0ffc,0x0ffd,0x0ffe,0x0fff,0x0fff,0x1000,0x1000,0x1000
    } ;

    uint16_t val;

    theta &= 0x3ff;

    if (theta < 0x100)
        val = sintbl[theta];
    else
    if (theta < 0x200)
        val = sintbl [0x200 - theta - 1];
    else
    if (theta < 0x300)
        val = (~sintbl[theta - 0x200] + 1); // negate
    else
        val = (~sintbl[0x400 - theta -1] + 1);  // negate

    return val;
}


/*
 * Natural-log table.  Smallest value is ln(2/4096) -> -7.624618986159398403
 * (values smaller than 2/4096 have logs less than -8, which smaller than we
 * can represent in our fixed-point format).  Largest is 2.0776, which is ln(8)
 */
int16_t fplog( int16_t n )
{
    static uint16_t lntbl[512] = {
        /*0.00048828*/ 0x8602,0xbdf3,0xc8cc,0xcf34,0xd3c3,0xd74f,0xda36,0xdcaa,0xdecb,0xe0ab,0xe259,0xe3df,0xe542,0xe689,0xe7b8,0xe8d2,
        /*0.25048828*/ 0xe9da,0xead2,0xebbb,0xec98,0xed6a,0xee32,0xeef0,0xefa6,0xf054,0xf0fb,0xf19b,0xf236,0xf2ca,0xf35a,0xf3e5,0xf46b,
        /*0.50048828*/ 0xf4ed,0xf56b,0xf5e5,0xf65c,0xf6cf,0xf73f,0xf7ac,0xf816,0xf87e,0xf8e3,0xf946,0xf9a6,0xfa04,0xfa60,0xfaba,0xfb12,
        /*0.75048828*/ 0xfb68,0xfbbd,0xfc0f,0xfc60,0xfcb0,0xfcfe,0xfd4a,0xfd96,0xfddf,0xfe28,0xfe6f,0xfeb5,0xfefa,0xff3d,0xff80,0xffc2,
        /*1.00048828*/ 0x0002,0x0041,0x0080,0x00be,0x00fa,0x0136,0x0171,0x01ab,0x01e4,0x021d,0x0254,0x028b,0x02c2,0x02f7,0x032c,0x0360,
        /*1.25048828*/ 0x0394,0x03c6,0x03f9,0x042a,0x045b,0x048c,0x04bc,0x04eb,0x051a,0x0548,0x0576,0x05a3,0x05d0,0x05fc,0x0628,0x0653,
        /*1.50048828*/ 0x067e,0x06a9,0x06d3,0x06fc,0x0725,0x074e,0x0776,0x079e,0x07c6,0x07ed,0x0814,0x083a,0x0860,0x0886,0x08ac,0x08d1,
        /*1.75048828*/ 0x08f5,0x091a,0x093e,0x0962,0x0985,0x09a8,0x09cb,0x09ee,0x0a10,0x0a32,0x0a54,0x0a75,0x0a96,0x0ab7,0x0ad8,0x0af8,
        /*2.00048828*/ 0x0b18,0x0b38,0x0b58,0x0b77,0x0b96,0x0bb5,0x0bd4,0x0bf2,0x0c10,0x0c2e,0x0c4c,0x0c6a,0x0c87,0x0ca4,0x0cc1,0x0cde,
        /*2.25048828*/ 0x0cfa,0x0d17,0x0d33,0x0d4f,0x0d6b,0x0d86,0x0da2,0x0dbd,0x0dd8,0x0df3,0x0e0d,0x0e28,0x0e42,0x0e5c,0x0e76,0x0e90,
        /*2.50048828*/ 0x0eaa,0x0ec3,0x0edd,0x0ef6,0x0f0f,0x0f28,0x0f41,0x0f59,0x0f72,0x0f8a,0x0fa2,0x0fba,0x0fd2,0x0fea,0x1001,0x1019,
        /*2.75048828*/ 0x1030,0x1047,0x105f,0x1075,0x108c,0x10a3,0x10ba,0x10d0,0x10e6,0x10fc,0x1113,0x1129,0x113e,0x1154,0x116a,0x117f,
        /*3.00048828*/ 0x1195,0x11aa,0x11bf,0x11d4,0x11e9,0x11fe,0x1213,0x1227,0x123c,0x1250,0x1265,0x1279,0x128d,0x12a1,0x12b5,0x12c9,
        /*3.25048828*/ 0x12dc,0x12f0,0x1304,0x1317,0x132a,0x133e,0x1351,0x1364,0x1377,0x138a,0x139d,0x13af,0x13c2,0x13d5,0x13e7,0x13fa,
        /*3.50048828*/ 0x140c,0x141e,0x1430,0x1442,0x1454,0x1466,0x1478,0x148a,0x149c,0x14ad,0x14bf,0x14d0,0x14e2,0x14f3,0x1504,0x1515,
        /*3.75048828*/ 0x1526,0x1537,0x1548,0x1559,0x156a,0x157b,0x158c,0x159c,0x15ad,0x15bd,0x15ce,0x15de,0x15ee,0x15fe,0x160f,0x161f,
        /*4.00048828*/ 0x162f,0x163f,0x164f,0x165e,0x166e,0x167e,0x168e,0x169d,0x16ad,0x16bc,0x16cc,0x16db,0x16ea,0x16fa,0x1709,0x1718,
        /*4.25048828*/ 0x1727,0x1736,0x1745,0x1754,0x1763,0x1772,0x1780,0x178f,0x179e,0x17ac,0x17bb,0x17c9,0x17d8,0x17e6,0x17f5,0x1803,
        /*4.50048828*/ 0x1811,0x181f,0x182d,0x183c,0x184a,0x1858,0x1866,0x1873,0x1881,0x188f,0x189d,0x18ab,0x18b8,0x18c6,0x18d4,0x18e1,
        /*4.75048828*/ 0x18ef,0x18fc,0x1909,0x1917,0x1924,0x1931,0x193f,0x194c,0x1959,0x1966,0x1973,0x1980,0x198d,0x199a,0x19a7,0x19b4,
        /*5.00048828*/ 0x19c1,0x19cd,0x19da,0x19e7,0x19f4,0x1a00,0x1a0d,0x1a19,0x1a26,0x1a32,0x1a3f,0x1a4b,0x1a57,0x1a64,0x1a70,0x1a7c,
        /*5.25048828*/ 0x1a88,0x1a95,0x1aa1,0x1aad,0x1ab9,0x1ac5,0x1ad1,0x1add,0x1ae9,0x1af5,0x1b01,0x1b0c,0x1b18,0x1b24,0x1b30,0x1b3b,
        /*5.50048828*/ 0x1b47,0x1b53,0x1b5e,0x1b6a,0x1b75,0x1b81,0x1b8c,0x1b98,0x1ba3,0x1bae,0x1bba,0x1bc5,0x1bd0,0x1bdc,0x1be7,0x1bf2,
        /*5.75048828*/ 0x1bfd,0x1c08,0x1c13,0x1c1e,0x1c29,0x1c34,0x1c3f,0x1c4a,0x1c55,0x1c60,0x1c6b,0x1c76,0x1c80,0x1c8b,0x1c96,0x1ca1,
        /*6.00048828*/ 0x1cab,0x1cb6,0x1cc1,0x1ccb,0x1cd6,0x1ce0,0x1ceb,0x1cf5,0x1d00,0x1d0a,0x1d15,0x1d1f,0x1d29,0x1d34,0x1d3e,0x1d48,
        /*6.25048828*/ 0x1d53,0x1d5d,0x1d67,0x1d71,0x1d7b,0x1d85,0x1d90,0x1d9a,0x1da4,0x1dae,0x1db8,0x1dc2,0x1dcc,0x1dd6,0x1ddf,0x1de9,
        /*6.50048828*/ 0x1df3,0x1dfd,0x1e07,0x1e11,0x1e1a,0x1e24,0x1e2e,0x1e38,0x1e41,0x1e4b,0x1e54,0x1e5e,0x1e68,0x1e71,0x1e7b,0x1e84,
        /*6.75048828*/ 0x1e8e,0x1e97,0x1ea1,0x1eaa,0x1eb4,0x1ebd,0x1ec6,0x1ed0,0x1ed9,0x1ee2,0x1eec,0x1ef5,0x1efe,0x1f07,0x1f10,0x1f1a,
        /*7.00048828*/ 0x1f23,0x1f2c,0x1f35,0x1f3e,0x1f47,0x1f50,0x1f59,0x1f62,0x1f6b,0x1f74,0x1f7d,0x1f86,0x1f8f,0x1f98,0x1fa1,0x1faa,
        /*7.25048828*/ 0x1fb2,0x1fbb,0x1fc4,0x1fcd,0x1fd6,0x1fde,0x1fe7,0x1ff0,0x1ff8,0x2001,0x200a,0x2012,0x201b,0x2024,0x202c,0x2035,
        /*7.50048828*/ 0x203d,0x2046,0x204e,0x2057,0x205f,0x2068,0x2070,0x2079,0x2081,0x2089,0x2092,0x209a,0x20a2,0x20ab,0x20b3,0x20bb,
        /*7.75048828*/ 0x20c4,0x20cc,0x20d4,0x20dc,0x20e5,0x20ed,0x20f5,0x20fd,0x2105,0x210d,0x2115,0x211d,0x2126,0x212e,0x2136,0x213e
    } ;

    return (n >= 0x0002) ? lntbl[ (n - 2) >> 6 ] : 0x8000;
}

/*
 * Exponential table -- from -8.0 to 2.xxx.  Layout is tricky.
 */
int16_t fpexp( int16_t n ) {
    static int16_t pos_exp[] = {
        /*0000*/ 0x1000,0x1041,0x1082,0x10c5,0x1108,0x114d,0x1193,0x11d9,0x1221,0x126a,0x12b5,0x1300,0x134d,0x139b,0x13ea,0x143a,
        /*0400*/ 0x148b,0x14de,0x1532,0x1588,0x15df,0x1637,0x1690,0x16eb,0x1748,0x17a5,0x1805,0x1866,0x18c8,0x192c,0x1991,0x19f8,
        /*0800*/ 0x1a61,0x1acc,0x1b38,0x1ba5,0x1c15,0x1c86,0x1cf9,0x1d6e,0x1de4,0x1e5d,0x1ed7,0x1f54,0x1fd2,0x2052,0x20d4,0x2159,
        /*0c00*/ 0x21df,0x2268,0x22f2,0x237f,0x240e,0x24a0,0x2533,0x25c9,0x2662,0x26fd,0x279a,0x2839,0x28dc,0x2980,0x2a28,0x2ad1,
        /*1000*/ 0x2b7e,0x2c2d,0x2ce0,0x2d94,0x2e4c,0x2f07,0x2fc4,0x3085,0x3149,0x320f,0x32d9,0x33a6,0x3476,0x354a,0x3621,0x36fb,
        /*1400*/ 0x37d8,0x38ba,0x399e,0x3a87,0x3b72,0x3c62,0x3d56,0x3e4d,0x3f48,0x4047,0x414a,0x4251,0x435d,0x446c,0x4580,0x4698,
        /*1800*/ 0x47b5,0x48d6,0x49fc,0x4b26,0x4c55,0x4d89,0x4ec1,0x4fff,0x5141,0x5289,0x53d6,0x5527,0x567f,0x57db,0x593e,0x5aa5,
        /*1c00*/ 0x5c13,0x5d86,0x5eff,0x607e,0x6203,0x638e,0x6520,0x66b7,0x6855,0x69fa,0x6ba5,0x6d57,0x6f10,0x70d0,0x7296,0x7464
    } ;
    static int16_t neg_exp[] = {
        /*8000*/ 0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,
        /*8400*/ 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,
        /*8800*/ 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,
        /*8c00*/ 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0004,0x0004,0x0004,0x0004,
        /*9000*/ 0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0005,0x0005,0x0005,0x0005,
        /*9400*/ 0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,
        /*9800*/ 0x0006,0x0006,0x0006,0x0006,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0008,0x0008,0x0008,
        /*9c00*/ 0x0008,0x0008,0x0008,0x0008,0x0008,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x000a,0x000a,0x000a,0x000a,
        /*a000*/ 0x000a,0x000a,0x000a,0x000b,0x000b,0x000b,0x000b,0x000b,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000d,0x000d,
        /*a400*/ 0x000d,0x000d,0x000d,0x000e,0x000e,0x000e,0x000e,0x000f,0x000f,0x000f,0x000f,0x000f,0x0010,0x0010,0x0010,0x0010,
        /*a800*/ 0x0011,0x0011,0x0011,0x0012,0x0012,0x0012,0x0012,0x0013,0x0013,0x0013,0x0014,0x0014,0x0014,0x0015,0x0015,0x0015,
        /*ac00*/ 0x0015,0x0016,0x0016,0x0017,0x0017,0x0017,0x0018,0x0018,0x0018,0x0019,0x0019,0x001a,0x001a,0x001a,0x001b,0x001b,
        /*b000*/ 0x001c,0x001c,0x001c,0x001d,0x001d,0x001e,0x001e,0x001f,0x001f,0x0020,0x0020,0x0021,0x0021,0x0022,0x0022,0x0023,
        /*b400*/ 0x0023,0x0024,0x0025,0x0025,0x0026,0x0026,0x0027,0x0028,0x0028,0x0029,0x0029,0x002a,0x002b,0x002b,0x002c,0x002d,
        /*b800*/ 0x002e,0x002e,0x002f,0x0030,0x0030,0x0031,0x0032,0x0033,0x0034,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,
        /*bc00*/ 0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0048,0x0049,0x004a,
        /*c000*/ 0x004b,0x004c,0x004d,0x004f,0x0050,0x0051,0x0052,0x0054,0x0055,0x0056,0x0058,0x0059,0x005a,0x005c,0x005d,0x005f,
        /*c400*/ 0x0060,0x0062,0x0063,0x0065,0x0067,0x0068,0x006a,0x006b,0x006d,0x006f,0x0071,0x0072,0x0074,0x0076,0x0078,0x007a,
        /*c800*/ 0x007c,0x007e,0x0080,0x0082,0x0084,0x0086,0x0088,0x008a,0x008c,0x008e,0x0091,0x0093,0x0095,0x0098,0x009a,0x009c,
        /*cc00*/ 0x009f,0x00a1,0x00a4,0x00a6,0x00a9,0x00ac,0x00ae,0x00b1,0x00b4,0x00b7,0x00ba,0x00bd,0x00c0,0x00c3,0x00c6,0x00c9,
        /*d000*/ 0x00cc,0x00cf,0x00d2,0x00d6,0x00d9,0x00dc,0x00e0,0x00e3,0x00e7,0x00eb,0x00ee,0x00f2,0x00f6,0x00fa,0x00fe,0x0102,
        /*d400*/ 0x0106,0x010a,0x010e,0x0112,0x0117,0x011b,0x0120,0x0124,0x0129,0x012d,0x0132,0x0137,0x013c,0x0141,0x0146,0x014b,
        /*d800*/ 0x0150,0x0156,0x015b,0x0160,0x0166,0x016c,0x0171,0x0177,0x017d,0x0183,0x0189,0x018f,0x0196,0x019c,0x01a2,0x01a9,
        /*dc00*/ 0x01b0,0x01b7,0x01bd,0x01c4,0x01cc,0x01d3,0x01da,0x01e2,0x01e9,0x01f1,0x01f9,0x0201,0x0209,0x0211,0x0219,0x0222,
        /*e000*/ 0x022a,0x0233,0x023c,0x0245,0x024e,0x0257,0x0261,0x026a,0x0274,0x027e,0x0288,0x0292,0x029d,0x02a7,0x02b2,0x02bd,
        /*e400*/ 0x02c8,0x02d3,0x02de,0x02ea,0x02f6,0x0302,0x030e,0x031a,0x0327,0x0333,0x0340,0x034d,0x035b,0x0368,0x0376,0x0384,
        /*e800*/ 0x0392,0x03a0,0x03af,0x03be,0x03cd,0x03dc,0x03ec,0x03fc,0x040c,0x041c,0x042d,0x043d,0x044e,0x0460,0x0471,0x0483,
        /*ec00*/ 0x0496,0x04a8,0x04bb,0x04ce,0x04e1,0x04f5,0x0509,0x051d,0x0532,0x0547,0x055c,0x0572,0x0588,0x059e,0x05b4,0x05cb,
        /*f000*/ 0x05e3,0x05fb,0x0613,0x062b,0x0644,0x065d,0x0677,0x0691,0x06ab,0x06c6,0x06e2,0x06fd,0x071a,0x0736,0x0753,0x0771,
        /*f400*/ 0x078f,0x07ad,0x07cc,0x07ec,0x080c,0x082c,0x084d,0x086e,0x0890,0x08b3,0x08d6,0x08fa,0x091e,0x0943,0x0968,0x098e,
        /*f800*/ 0x09b4,0x09db,0x0a03,0x0a2c,0x0a55,0x0a7e,0x0aa9,0x0ad3,0x0aff,0x0b2b,0x0b58,0x0b86,0x0bb5,0x0be4,0x0c14,0x0c45,
        /*fc00*/ 0x0c76,0x0ca8,0x0cdb,0x0d0f,0x0d44,0x0d79,0x0daf,0x0de7,0x0e1f,0x0e58,0x0e91,0x0ecc,0x0f08,0x0f44,0x0f82,0x0fc0
    } ;

    if (n >= 0 && n < 0x2000) return pos_exp[n >> 6];

    if (n < 0) return neg_exp[ (uint16_t(n) - 0x8000u) >> 6 ];

    cerr << "can't compute exp( 0x" << hex << n << " " << fp2str( n ) << ")" << endl;

    exit( 0 );
}

int
main( int, char ** )
{
#ifdef TESTING
    for (uint16_t a = 2; a < 0x7000; a += 0x0529) {
        cout << "ln(" << fp2str(a) << " (0x" << hex << a << ")) = "
             << fp2str( fplog( a ) ) << " ... " << log( double(a) / double(0x1000) ) << endl;
    }

    for (uint16_t a = 0; a < 0x2000; a += 0x0727) {
        cout << "exp(" << fp2str(a) << " (0x" << hex << a << ")) = "
             << fp2str( fpexp( a ) ) << " ... " << exp( double(a) / double(0x1000) ) << endl;
    }

    for (int16_t a = -1; a > -30000; a -= 0x0ab7) {
        cout << "exp(" << fp2str(a) << " (0x" << hex << a << ")) = "
             << fp2str( fpexp( a ) ) << " ... " << exp( double(a) / double(0x1000) ) << endl;
    }

    for (uint16_t a = 10; a < 0x7fff; a += 0x0ab7) {
        cout << "exp( log(" << fp2str(a) << " (0x" << hex << a << "))) = "
             << fp2str( fpexp( fplog( a ) ) ) << endl;
    }
#else

    // Implementation of y = (1/2 * (1 + sin( x ))) ^ n is left as an exercise for the reader.
    // Note that fplog() doesn't work on numbers smaller than 2/4096, and fpexp() doesn't work
    // on numbers larger than about (2 - 1/4096)

#endif

    return 0;
}

我用这个 Perl 脚本生成了查找表:

#!/usr/bin/perl -w

use Math::Trig ':pi';
use POSIX;

#
# Fixed-point values have 12 fractional bits ... 2^12 => 4096
#
my $LSB = 1.0 / 4096.0;

#
# print sin table values
#
if (0) {
    for ($i = 0; $i < 0x100; $i += 1) {
        $s = sin( $i * pip2 / 255 );
        printf( "0x%04x,", POSIX::floor( 0x1000 * $s + 0.5) );
        print "\n" if (($i & 15) == 15);
    }
}

#
# print log table values
#
if (0) {
    $x = $LSB * 2.0;
    for ($n = 0; $n < 32000; ++$n) {
        printf( "/*%10.8f*/ ", $x ) if (($n & 15) == 0);
        printf( "0x%04x,", POSIX::floor( 0x1000 * log($x) + 0.5) & 0xffff );
        print "\n" if (($n & 15) == 15);
        $x += $LSB * 64.0;
        last if ($x >= 8.0);
    }
}

#
# print exp table values -- this is tricky because we want all the negative
# numbers (0xffff ~ 0x8000) but only positive numbers between 0x0000 and 0x2000.
#
if (1) {
    for ($n = 0; $n < 0x2000; $n += 64) {
        printf( "/*%04x*/ ", $n & 0xffff ) if ((($n >> 6) & 15) == 0);
        # printf( "%8.5f,", $n / 4096.0 );
        printf( "0x%04x,", POSIX::floor( exp( $n / 4096.0 ) * 0x1000 + 0.5 ) );
        print "\n" if ((($n >> 6) & 15) == 15);
    }
    print "\n\n";
    for ($n = -32768; $n < 0; $n += 64) {
        printf( "/*%04x*/ ", $n & 0xffff ) if ((($n >> 6) & 15) == 0);
        # printf( "%8.5f,", $n / 4096.0 );
        printf( "0x%04x,", POSIX::floor( exp( $n / 4096 ) * 0x1000 + 0.5 ) );
        print "\n" if ((($n >> 6) & 15) == 15);
    }
}

棘手的一点是将信号移动和缩放到 fplog()fpexp() 工作得相当好的范围。你会做一个 16x16->32 的乘法来取幂,所以我想你会把高 16 位作为你的定点数,你将它提供给 fpexp() 以获得最终输出。

Does anyone have an idea how to realize such a shape modification only with integer math?
n could also have a range of 1 to 10 for example

$y(x) = (1/2*(1 + sin(x)))^n$

OP 有一个正弦近似函数 sin_bam(),然后用它来形成 1/2*(1 + sin(x)),即 hacovercosin(θ)。剩下的就是比例幂函数。

#include <inttypes.h>
#define SCALE 16384

int pow_scale(int x, unsigned n) {
  unsigned y = SCALE;
  while (n>0) {
    if (n%2) {
      y = unsigned_mult16x16_into_32(x,y)/SCALE; // 16-bit x 16-bit --> 32-bit product.
    }
    n /= 2;
    x = unsigned_mult16x16_into_32(x,x)/SCALE;
  }
  return x;
}

// x is the angle in 1024 BAM per period
// output is scaled to range [0....SCALE]
int shaped(int x, unsigned n) {
  return pow_scale(SCALE/2 + sin_bam(x)/2), n);
}