43oh

# 2^N for real numbers using integer math

## Recommended Posts

When working with electronic music (MIDI synth and such) it is sometimes necessary to adjust pitch by units of octaves, semitones, or cents.

An octave is a 2:1 ratio. So the ratio between any number of octaves is 2^N. This is a simple bit shift. Easy.

A semitone is 1/12 of an octave (typically), so the ratio for that is 2^(N/12). A cent is 1/1200 of an octave, so the ratio for that is 2^(N/1200). Can't use bit shifting for that!

The C stdlib provides the pow() function that can be used for these calculations, but it uses rather slow floating point math.

This code will do it with relatively fast fixed point integer math. This code could easily be adapted to almost any base and exponent by changing the look-up tables. It uses the property of exponents that 2 ^ (1 + 2 + 4 + 8) == (2 ^ 1) * (2 ^ 2) * (2 ^ 4) * (2 ^ 8)

```//
// 2 ^ (n / (1200 * 8192))
//
// n = 1 / 8,192 cent
//   = 1 / 819,200 semitone
//   = 1 / 9,830,400 octave
//
// range of n: -134,217,727 to +78,643,199
//            = -13.65 to +7.99 octaves
//
// returned value is 8.24 fixed point
//
// + exponents in 8.24 format
static const uint32_t etp[27] = {
0x01000001,                     // 00000001  1.0000000705
0x01000002,                     // 00000002  1.0000001410
0x01000005,                     // 00000004  1.0000002820
0x01000009,                     // 00000008  1.0000005641
0x01000013,                     // 00000010  1.0000011282
0x01000026,                     // 00000020  1.0000022563
0x0100004C,                     // 00000040  1.0000045127
0x01000097,                     // 00000080  1.0000090254
0x0100012F,                     // 00000100  1.0000180509
0x0100025E,                     // 00000200  1.0000361021
0x010004BB,                     // 00000400  1.0000722054
0x01000977,                     // 00000800  1.0001444161
0x010012EE,                     // 00001000  1.0002888530
0x010025DE,                     // 00002000  1.0005777895
0x01004BC1,                     // 00004000  1.0011559129
0x01009798,                     // 00008000  1.0023131618
0x01012F8B,                     // 00010000  1.0046316744
0x0102607D,                     // 00020000  1.0092848012
0x0104C6A1,                     // 00040000  1.0186558100
0x0109A410,                     // 00080000  1.0376596592
0x0113A513,                     // 00100000  1.0767375682
0x0128CC11,                     // 00200000  1.1593637909
0x01581889,                     // 00400000  1.3441243996
0x01CE81F4,                     // 00800000  1.8066704016
0x0343994D,                     // 01000000  3.2640579400
0x0AA77169,                     // 02000000  10.6540742354
0x71826157                      // 04000000  113.5092978129
};
// - exponents in 8.24 format
static const uint32_t etn[27] = {
0x00FFFFFF,                     // 00000001  0.9999999295
0x00FFFFFE,                     // 00000002  0.9999998590
0x00FFFFFB,                     // 00000004  0.9999997180
0x00FFFFF7,                     // 00000008  0.9999994359
0x00FFFFED,                     // 00000010  0.9999988718
0x00FFFFDA,                     // 00000020  0.9999977437
0x00FFFFB4,                     // 00000040  0.9999954873
0x00FFFF69,                     // 00000080  0.9999909747
0x00FFFED1,                     // 00000100  0.9999819495
0x00FFFDA2,                     // 00000200  0.9999638992
0x00FFFB45,                     // 00000400  0.9999277998
0x00FFF689,                     // 00000800  0.9998556048
0x00FFED13,                     // 00001000  0.9997112304
0x00FFDA28,                     // 00002000  0.9994225441
0x00FFB455,                     // 00004000  0.9988454217
0x00FF68C1,                     // 00008000  0.9976921765
0x00FED1DC,                     // 00010000  0.9953896791
0x00FDA51C,                     // 00020000  0.9908006133
0x00FB4FC4,                     // 00040000  0.9816858552
0x00F6B582,                     // 00080000  0.9637071184
0x00EDC157,                     // 00100000  0.9287314100
0x00DCCF8E,                     // 00200000  0.8625420320
0x00BE7564,                     // 00400000  0.7439787570
0x008DB277,                     // 00800000  0.5535043908
0x004E6E13,                     // 01000000  0.3063671106
0x00180743,                     // 02000000  0.0938608065
0x0002415D                      // 04000000  0.0088098510
};
uint32_t tpow(int32_t n)
{
const uint32_t *et = etp;           // Assume + exponent
if(n < 0) n = -n, et = etn;         // Adjust for - exponent
//
uint32_t r = 1L << 24;              // Init result to 1.0 in 8.24 format
//
do {                                //
if(n & 1) r = mul824(r, *et);   // Multiply by exponent if lsb of n is 1
++et;                           // Next exponent
} while(n >>= 1);                   // Next bit, loop until no more 1 bits
//
return r;                           // Return result
}
```

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
• Blog

• #### Activity

×
• Create New...