Skip to content

Instantly share code, notes, and snippets.

@LFSaw
Last active August 29, 2015 14:00
Show Gist options
  • Save LFSaw/11328362 to your computer and use it in GitHub Desktop.
Save LFSaw/11328362 to your computer and use it in GitHub Desktop.
Fixed-point arithmetics in mozzi

Fixed-point arithmetics in mozzi

(Mozzi is a sound synthesis toolkit for the Arduino)

General remarks

Naming

The naming of the fixed-point types is based on the Qm.f-notation ("the unambiguous form") as described in the notation section of the wikipedia article on fixed-point arithmetic, replacing . with n.[^ Since `.` does not work in C.]

Conversion

There are no automatic conversions.

For every fixed-point type with fractional part there is a floating point conversion method

float_to_Q<a>n<b>
Q<a>n<b>_to_float

Additionally, there are conversion methods as displayed in the below graphics (and listed in the dedicated section below).

Converting a fixed-point number to another type by casting works as long as

  • it has the same amount of fractional bits and
  • the number of used integer bits in the old representation is less or equal to the number of integer bits available in the new representation.

Representations of constants

Representation of the closest approximation of 1:

// unsigned
 Q0n16_FIX1;
 Q0n32_FIX1;
 Q1n15_FIX1;

  Q8n8_FIX1;
Q16n16_FIX1;
 Q8n24_FIX1;
Q15n16_FIX1;
 Q23n8_FIX1;

// signed
  Q0n7_FIX1;
 Q0n15_FIX1;
 Q1n14_FIX1;

  Q7n8_FIX1;
 Q15n0_FIX1;

Representation of the closest approximation of PI resp. 2PI:

// signed
Q16n16_PI
Q16n16_2PI 

// signed
Q3n13_2PI

Unsigned

Range around 1

Q0n8

.ffffffff // [0.0 ... 0.996]

Unsigned fractional number with 8 fractional bits.

Conversion to

Q8n24_to_Q0n8
Q24n8_to_Q0n8

Conversion from

// unsigned
Q0n8_to_Q1n15
Q0n8_to_Q8n8
Q0n8_to_Q16n16
Q0n8_to_Q8n24
Q0n8_to_Q24n8

// signed
Q0n8_to_Q15n16

Conversion to

// unsigned
Q16n16_to_Q0n8

Q0n16

.ffffffffffffffff // [0.0 ... 0.999]

Unsigned fractional number with 16 fractional bits.

Conversion to

// unsigned
Q16n16_to_Q0n8

Q0n32

.ffffffffffffffffffffffffffffffff // [0 ... 0.999999999767169]

Unsigned fractional number with 0 integer bits and 32 fractional bits.

Q1n15

i.fffffffffffffff // [0 ... 1.999]

Unsigned fractional number with 1 integer bit and 15 fractional bits.

Conversion methods to

Q0n8_to_Q1n15

Conversion methods from

Q1n15_to_Q0n8

Q3n13

iii.fffffffffffff // [0 ... 7.999]

Unsigned fractional number with 3 integer bits and 13 fractional bits.

Good compromise

Q8n8

iiiiiiii.ffffffff // [0 ... 255.996]

Unsigned fractional number with 8 integer bits and 8 fractional bits.

Conversion methods to

Q0n8_to_Q8n8

Conversion methods from

Q8n8_to_Q8n0
Q8n8_to_Q16n16

Q16n16

`iiiiiiiiiiiiiiii.ffffffffffffffff // [0 ... 65535.999]

Unsigned fractional number with 16 integer bits and 16 fractional bits.

Conversion methods to

// unsigned
 Q0n8_to_Q16n16
 Q8n0_to_Q16n16
 Q8n8_to_Q16n16
Q16n0_to_Q16n16
Q24n8_to_Q16n16

Conversion methods from

// unsigned
Q16n16_to_Q0n8
Q16n16_to_Q16n0
Q16n16_to_Q24n8

Usage:

int    i_val = 127; // e.g from int
Q16n16 q_val = Q16n0_to_Q16n16(i_val);

Q8n24

Q8n24 -- signed fractional number with 8 integer bits and 24 fractional bits. [0 ... 255.999]

Conversion methods to

Q0n8_to_Q8n24

Conversion methods from

Q8n24_to_Q0n8

Q24n8

iiiiiiiiiiiiiiiiiiiiiiii.ffffffff // [0 ... 16777215]

unsigned fractional number with 24 integer bits and 8 fractional bits. [0 to represents 0 to 16777215.

// e.g. read from an analog input. 
// could also be ints and unsigned ints, as long as they are positive 
long  i_val = 127;
Q24n8 q_val = Q16n0_to_Q24n8(i_val);

Conversion methods to Q24n8 are:

// unsigned
  Q0n8_to_Q24n8(a);
Q16n16_to_Q24n8(a);
 Q16n0_to_Q24n8(a);

Conversion methods from Q24n8 are:

// unsigned
Q24n8_to_Q0n8  
Q24n8_to_Q16n16
Q24n8_to_Q16n0 
Q24n8_to_Q32n0 

calculate fractions for amplitude or frequency modulation and use it to set the frequency of an oscillator

Q24n8 q_freq = q_val / 10 + 100;
aOsc.setFreq(q_freq);

No fraction bits

Q8n0

iiiiiiii. // [0.0 ... 255.0]

Same as unsigned char. Unsigned number with 0 fractional bits.

Conversion methods to

Q8n8_to_Q8n0

Conversion methods from

// unsigned
Q8n0_to_Q7n8
Q8n0_to_Q8n8
Q8n0_to_Q16n16

// signed
Q8n0_to_Q15n16

Q16n0

iiiiiiiiiiiiiiii // [0 ... 65536.0]

Unsigned number with 16 integer bits and 0 fractional bits.

Conversion methods to

// unsigned
Q24n8_to_Q16n0

// signed
Q23n8_to_Q16n0

Conversion methods from

// unsigned
Q16n0_to_Q16n16
Q16n0_to_Q24n8

// signed
Q16n0_to_Q15n16
Q16n0_to_Q23n8

Q32n0

iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii // [0 ... 4294967295]

Same as unsigned long int. Unsigned number with 32 integer bits and 0 fractional bits.

Conversion methods to

// unsigned
Q24n8_to_Q32n0

Signed

Range around 1

Q0n7

[+|-] .fffffff // [-0.5 ... 0.496]

Signed fractional number with 7 fractional bits.

Conversion methods to

Q1n14_to_Q0n7

Conversion methods from

Q0n7_to_Q1n14
Q0n7_to_Q15n16

Q0n15

[+|-] .fffffffffffffff // [-0.32768 ... 0.32767]

Signed fractional number with 0 integer bits and 15 fractional bits.

Q0n31

[+|-] .fffffffffffffffffffffffffffffff // [-32768 ... 32767]

Signed fractional number with 0 integer bits and 31 fractional bits.

Q1n14

[+|-] i.ffffffffffffff // [-1.999 ... 1.999]

Signed fractional number with 1 integer bit and 14 fractional bits.

Conversion methods to

Q0n7_to_Q1n14()

Conversion methods from

Q1n14_to_Q0n7

Good compromise

Q7n8

[+|-] iiiiiii.ffffffff // [-127.996 ... 127.996]

Signed fractional number with 7 integer bits and 8 fractional bits.

Conversion methods to

// unsigned
Q8n0_to_Q7n8

// signed
Q15n16_to_Q7n8
Q23n8_to_Q7n8
Q7n0_to_Q7n8

Conversion methods from

// signed
Q7n8_to_Q7n0
Q7n8_to_Q15n16

Q23n8

[+|-] iiiiiiiiiiiiiiiiiiiiiii.ffffffff // [-8388607.996 ... 8388607.996]

Signed fractional number with 23 integer bits and 8 fractional bits.

Conversion methods to

// unsigned
Q16n0_to_Q23n8
Q15n16_to_Q23n8

Conversion methods from

// unsigned
Q23n8_to_Q16n0

// signed
Q23n8_to_Q7n8
Q23n8_to_Q15n0
Q23n8_to_Q31n0

Q15n16

[+|-] iiiiiiiiiiiiiii.ffffffffffffffff // [-32767.999 ... 32767.999]

Signed fractional number with 15 integer bits and 16 fractional bits.

Conversion methods to

// unsigned
Q0n8_to_Q15n16
Q8n0_to_Q15n16

// signed
Q0n7_to_Q15n16
Q7n8_to_Q15n16
Q7n0_to_Q15n16
Q15n0_to_Q15n16

Conversion methods from

// unsigned
Q15n16_to_Q0n8

// signed
Q15n16_to_Q7n8
Q15n16_to_Q23n8
Q15n16_to_Q15n0

No fractional bits

Q7n0

[+|-] . // [-128 ... 127]

Same as char. Signed fractional number with 7 integer bits 0 fractional bits.

// unsigned
Q16n0_to_Q15n16

// signed
Q7n0_to_Q7n8
Q7n0_to_Q15n16

Q15n0

[+|-] fffffffffffffff. // [-2147483648 ... 2147483647]

Signed number with 15 integer bits and 0 fractional bits.

Conversion methods to

Q15n0_to_Q15n16

Conversion methods from

Q15n16_to_Q15n0

Q31n0

[+|-] iiiiiiiiiiiiiiiiiiiiiiiiiiiiiii. // [-2147483648 ... 2147483647]

Signed (normal long int) number with 31 integer bits and 0 fractional bits.

Conversion methods to

Q23n8_to_Q31n0
digraph conversions {
node [shape = box, style= filled]
float [fillcolor=blue]
Q0n7 [fillcolor=red]
Q7n0 [fillcolor=red]
Q7n8 [fillcolor=red]
Q1n14 [fillcolor=red]
Q15n0 [fillcolor=red]
Q23n8 [fillcolor=red]
Q15n16 [fillcolor=red]
Q32n0 [fillcolor=red]
Q0n8 [fillcolor=green]
Q8n0 [fillcolor=green]
Q8n8 [fillcolor=green]
Q0n16 [fillcolor=green]
Q16n0 [fillcolor=green]
Q8n24 [fillcolor=green]
Q16n16 [fillcolor=green]
Q24n8 [fillcolor=green]
Q1n15 [fillcolor=green]
Q31n0 [fillcolor=green]
float -> Q0n7;
float -> Q0n8;
float -> Q7n8;
float -> Q8n8;
float -> Q1n14;
float -> Q1n15;
float -> Q8n24;
float -> Q23n8;
float -> Q24n8;
float -> Q16n16;
float -> Q0n16;
float -> Q15n16;
Q0n7 -> Q1n14;
Q0n7 -> Q15n16;
Q0n7 -> float;
Q0n8 -> Q1n15;
Q0n8 -> Q8n8;
Q0n8 -> Q8n24;
Q0n8 -> Q24n8;
Q0n8 -> Q15n16;
Q0n8 -> Q16n16;
Q0n8 -> float;
Q7n0 -> Q7n8;
Q7n0 -> Q15n16;
Q8n0 -> Q7n8;
Q8n0 -> Q8n8;
Q8n0 -> Q15n16;
Q8n0 -> Q16n16;
Q7n8 -> Q7n0;
Q7n8 -> Q15n16;
Q7n8 -> float;
Q8n8 -> Q8n0;
Q8n8 -> Q16n16;
Q8n8 -> float;
Q1n14 -> Q0n7;
Q1n14 -> float;
Q1n15 -> Q0n8;
Q1n15 -> float;
Q0n16 -> float;
Q15n0 -> Q15n16;
Q16n0 -> Q15n16;
Q16n0 -> Q23n8;
Q16n0 -> Q24n8;
Q16n0 -> Q16n16;
Q16n0 -> float;
Q8n24 -> Q0n8;
Q8n24 -> float;
Q23n8 -> Q31n0;
Q23n8 -> Q16n0;
Q23n8 -> Q15n0;
Q23n8 -> Q7n8;
Q23n8 -> float;
Q24n8 -> Q0n8;
Q24n8 -> Q16n0;
Q24n8 -> Q32n0;
Q24n8 -> Q16n16;
Q24n8 -> float;
Q15n16 -> Q0n8;
Q15n16 -> Q15n0;
Q15n16 -> Q7n8;
Q15n16 -> Q23n8;
Q15n16 -> float;
Q16n16 -> Q0n8;
Q16n16 -> Q16n0;
Q16n16 -> Q24n8;
Q16n16 -> float;
/*
{ rank=same; Q0n8 Q8n0 Q8n8 Q0n16 Q16n0 Q8n24 Q16n16 Q24n8 Q1n15 }
{ rank=same; Q0n7 Q7n0 Q7n8 Q1n14 Q15n0 Q23n8 Q15n16 }
*/
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment