File arith_core.h¶
FileList > arith > arith_core.h
Go to the source code of this file
Arith module — public C API for fixed-point arithmetic on Q15 (int16_t) and Q8 (int8_t) arrays. All elementwise operations write into a caller-supplied output buffer of the same length as the shorter input. Saturation clamps results to the representable range rather than wrapping, matching the two's-complement DSP convention.
#include "clib_common.h"
Public Functions¶
| Type | Name |
|---|---|
| void | add_q15 (const int16_t * a, size_t a_len, const int16_t * b, size_t b_len, int16_t * out) Elementwise saturating add of two Q15 arrays. Each pair of samples is added as int32_t and then clamped to [-32768, 32767] before storing, so overflow wraps to the saturation boundary rather than producing garbage bits. |
| void | add_q8 (const int8_t * a, size_t a_len, const int8_t * b, size_t b_len, int8_t * out) Elementwise saturating add of two Q8 arrays. Each pair of samples is added as int16_t and then clamped to [-128, 127] before storing, preventing overflow wrap on near-boundary values. |
| int64_t | dot_q15 (const int16_t * a, size_t a_len, const int16_t * b, size_t b_len) Inner product of two Q15 arrays, returning the raw Q30 sum. Accumulates products as int64_t — no scaling or saturation is applied here. The caller shifts the result right 15 bits (e.g. via shr_i64) to recover a Q15 scalar, or keeps the Q30 value for further arithmetic. |
| int32_t | dot_q8 (const int8_t * a, size_t a_len, const int8_t * b, size_t b_len) Inner product of two Q8 arrays, returning the raw Q14 sum. Accumulates products as int32_t — no scaling or saturation is applied. The result lives in Q14 space (each product is Q7*Q7 = Q14); the caller shifts right 7 to recover a Q7 scalar if needed. |
| void | mul_q15 (const int16_t * a, size_t a_len, const int16_t * b, size_t b_len, int16_t * out) Elementwise Q15 multiply with round-half-up and saturation. Computes out[i] = sat16((a[i] *b[i] + 16384) >> 15). The bias 16384 (= 1 << 14) implements round-half-up before the 15-bit right shift, so 0.5 * 0.5 = 0.25 in Q15 arithmetic (16384 * 16384 -> 8192) rather than truncating toward zero. |
| void | mul_q8 (const int8_t * a, size_t a_len, const int8_t * b, size_t b_len, int8_t * out) Elementwise Q8 multiply with round-half-up and saturation. Computes out[i] = sat8((a[i] *b[i] + 64) >> 7). The bias 64 (= 1 << 6) rounds at the half-LSB position before the 7-bit shift, mirroring the rounding convention of mul_q15 but for 8-bit fixed-point. In Q8 terms, 0.5 * 0.5 = 0.25 (64 * 64 -> 32). |
| void | shl_i64 (const int64_t * a, size_t a_len, int64_t * out, int n) Elementwise logical left shift of an int64_t array. No saturation is applied — the caller is responsible for ensuring that no element will overflow 64 bits. Shifts >= 63 produce zero. Designed to scale int64_t accumulators (e.g. after a chain of multiply-accumulate operations) before final truncation. |
| void | shl_q15 (const int16_t * a, size_t a_len, int16_t * out, int n) Elementwise arithmetic left shift of a Q15 array with saturation. Computes out[i] = sat16(a[i] << n), equivalent to multiplying by 2^n in fixed-point. Any shifted value that exceeds the int16_t range is clamped, preventing silent wraparound. |
| void | shl_q8 (const int8_t * a, size_t a_len, int8_t * out, int n) Elementwise arithmetic left shift of a Q8 array with saturation. Computes out[i] = sat8(a[i] << n). Shifts that would exceed the int8_t range are clamped, preventing silent wraparound into wrong-sign results. |
| void | shr_i64 (const int64_t * a, size_t a_len, int64_t * out, int n) Elementwise arithmetic right shift of an int64_t array with round-half-up. Adds 1 << (n-1) as a bias before shifting, so values at the half-LSB boundary round up. Primarily used to normalise the raw Q30 output of dot_q15 back to Q15 by shifting right 15 bits. |
| void | shr_q15 (const int16_t * a, size_t a_len, int16_t * out, int n) Elementwise arithmetic right shift of a Q15 array with round-half-up. Adds 1 << (n-1) as a rounding bias before shifting, so values exactly at the half-LSB boundary round up rather than truncating. Equivalent to dividing by 2^n in Q15 fixed-point with correct rounding. |
| void | shr_q8 (const int8_t * a, size_t a_len, int8_t * out, int n) Elementwise arithmetic right shift of a Q8 array with round-half-up. Adds 1 << (n-1) as a rounding bias before shifting, matching the rounding convention of shr_q15 at 8-bit precision. |
| void | sub_q15 (const int16_t * a, size_t a_len, const int16_t * b, size_t b_len, int16_t * out) Elementwise saturating subtract of two Q15 arrays. Computes out[i] = sat16(a[i] -b[i] ) for i in[0, min(len(a), len(b))) . The intermediate difference is computed as int32_t to detect overflow before clamping, preserving the correct sign at the saturation boundary. |
| void | sub_q8 (const int8_t * a, size_t a_len, const int8_t * b, size_t b_len, int8_t * out) Elementwise saturating subtract of two Q8 arrays. Computes out[i] = sat8(a[i] -b[i] ) for i in[0, min(len(a), len(b))) . The intermediate difference is computed as int16_t so overflow is detected before clamping. |
Public Static Functions¶
| Type | Name |
|---|---|
| int16_t | sat16 (int32_t x) |
| int8_t | sat8 (int16_t x) |
Public Functions Documentation¶
function add_q15¶
Elementwise saturating add of two Q15 arrays. Each pair of samples is added as int32_t and then clamped to [-32768, 32767] before storing, so overflow wraps to the saturation boundary rather than producing garbage bits.
Parameters:
aFirst input array (int16_t).a_lenNumber of elements in a.bSecond input array (int16_t), same length as a.b_lenNumber of elements in b.outOutput array (int16_t), length min(a_len, b_len).
>>> from doppler.arith import add_q15
>>> import numpy as np
>>> a = np.array([100, 20000, -20000], dtype=np.int16)
>>> b = np.array([50, 20000, -20000], dtype=np.int16)
>>> add_q15(a, b).tolist()
[150, 32767, -32768]
function add_q8¶
Elementwise saturating add of two Q8 arrays. Each pair of samples is added as int16_t and then clamped to [-128, 127] before storing, preventing overflow wrap on near-boundary values.
Parameters:
aFirst input array (int8_t).a_lenNumber of elements in a.bSecond input array (int8_t), same length as a.b_lenNumber of elements in b.outOutput array (int8_t), length min(a_len, b_len).
>>> from doppler.arith import add_q8
>>> import numpy as np
>>> a = np.array([50, 100, -100], dtype=np.int8)
>>> b = np.array([50, 30, -50], dtype=np.int8)
>>> add_q8(a, b).tolist()
[100, 127, -128]
function dot_q15¶
Inner product of two Q15 arrays, returning the raw Q30 sum. Accumulates products as int64_t — no scaling or saturation is applied here. The caller shifts the result right 15 bits (e.g. via shr_i64) to recover a Q15 scalar, or keeps the Q30 value for further arithmetic.
Parameters:
aFirst input array (int16_t).a_lenNumber of elements in a.bSecond input array (int16_t), same length as a.b_lenNumber of elements in b.
Returns:
Raw Q30 accumulation (int64_t).
>>> from doppler.arith import dot_q15
>>> import numpy as np
>>> a = np.array([100, 200, 300], dtype=np.int16)
>>> b = np.array([1, 2, 3], dtype=np.int16)
>>> dot_q15(a, b)
1400
function dot_q8¶
Inner product of two Q8 arrays, returning the raw Q14 sum. Accumulates products as int32_t — no scaling or saturation is applied. The result lives in Q14 space (each product is Q7*Q7 = Q14); the caller shifts right 7 to recover a Q7 scalar if needed.
Parameters:
aFirst input array (int8_t).a_lenNumber of elements in a.bSecond input array (int8_t), same length as a.b_lenNumber of elements in b.
Returns:
Raw Q14 accumulation (int32_t).
>>> from doppler.arith import dot_q8
>>> import numpy as np
>>> a = np.array([10, 20, 30], dtype=np.int8)
>>> b = np.array([1, 2, 3], dtype=np.int8)
>>> dot_q8(a, b)
140
function mul_q15¶
Elementwise Q15 multiply with round-half-up and saturation. Computes out[i] = sat16((a[i] *b[i] + 16384) >> 15). The bias 16384 (= 1 << 14) implements round-half-up before the 15-bit right shift, so 0.5 * 0.5 = 0.25 in Q15 arithmetic (16384 * 16384 -> 8192) rather than truncating toward zero.
Parameters:
aFirst input array (int16_t).a_lenNumber of elements in a.bSecond input array (int16_t), same length as a.b_lenNumber of elements in b.outOutput array (int16_t), length min(a_len, b_len).
>>> from doppler.arith import mul_q15
>>> import numpy as np
>>> a = np.array([16384, 16384, 32767], dtype=np.int16)
>>> b = np.array([16384, -16384, 32767], dtype=np.int16)
>>> mul_q15(a, b).tolist()
[8192, -8192, 32766]
function mul_q8¶
Elementwise Q8 multiply with round-half-up and saturation. Computes out[i] = sat8((a[i] *b[i] + 64) >> 7). The bias 64 (= 1 << 6) rounds at the half-LSB position before the 7-bit shift, mirroring the rounding convention of mul_q15 but for 8-bit fixed-point. In Q8 terms, 0.5 * 0.5 = 0.25 (64 * 64 -> 32).
Parameters:
aFirst input array (int8_t).a_lenNumber of elements in a.bSecond input array (int8_t), same length as a.b_lenNumber of elements in b.outOutput array (int8_t), length min(a_len, b_len).
>>> from doppler.arith import mul_q8
>>> import numpy as np
>>> a = np.array([64, 64, -64], dtype=np.int8)
>>> b = np.array([64, -64, 64], dtype=np.int8)
>>> mul_q8(a, b).tolist()
[32, -32, -32]
function shl_i64¶
Elementwise logical left shift of an int64_t array. No saturation is applied — the caller is responsible for ensuring that no element will overflow 64 bits. Shifts >= 63 produce zero. Designed to scale int64_t accumulators (e.g. after a chain of multiply-accumulate operations) before final truncation.
Parameters:
aInput array (int64_t).a_lenNumber of elements in a.outOutput array (int64_t), same length as a.nShift count (non-negative integer; >= 63 yields 0).
>>> from doppler.arith import shl_i64
>>> import numpy as np
>>> a = np.array([100, 200, -200], dtype=np.int64)
>>> shl_i64(a, 3).tolist()
[800, 1600, -1600]
function shl_q15¶
Elementwise arithmetic left shift of a Q15 array with saturation. Computes out[i] = sat16(a[i] << n), equivalent to multiplying by 2^n in fixed-point. Any shifted value that exceeds the int16_t range is clamped, preventing silent wraparound.
Parameters:
aInput array (int16_t).a_lenNumber of elements in a.outOutput array (int16_t), same length as a.nShift count (non-negative integer).
>>> from doppler.arith import shl_q15
>>> import numpy as np
>>> a = np.array([8192, 16384, 20000], dtype=np.int16)
>>> shl_q15(a, 1).tolist()
[16384, 32767, 32767]
function shl_q8¶
Elementwise arithmetic left shift of a Q8 array with saturation. Computes out[i] = sat8(a[i] << n). Shifts that would exceed the int8_t range are clamped, preventing silent wraparound into wrong-sign results.
Parameters:
aInput array (int8_t).a_lenNumber of elements in a.outOutput array (int8_t), same length as a.nShift count (non-negative integer).
>>> from doppler.arith import shl_q8
>>> import numpy as np
>>> a = np.array([10, 50, 64], dtype=np.int8)
>>> shl_q8(a, 1).tolist()
[20, 100, 127]
function shr_i64¶
Elementwise arithmetic right shift of an int64_t array with round-half-up. Adds 1 << (n-1) as a bias before shifting, so values at the half-LSB boundary round up. Primarily used to normalise the raw Q30 output of dot_q15 back to Q15 by shifting right 15 bits.
Parameters:
aInput array (int64_t).a_lenNumber of elements in a.outOutput array (int64_t), same length as a.nShift count (non-negative integer; >= 63 is clamped to 63).
>>> from doppler.arith import dot_q15, shr_i64
>>> import numpy as np
>>> raw = dot_q15(
... np.array([16384, 16384], dtype=np.int16),
... np.array([16384, 16384], dtype=np.int16),
... )
>>> shr_i64(np.array([raw], dtype=np.int64), 15).tolist()
[16384]
function shr_q15¶
Elementwise arithmetic right shift of a Q15 array with round-half-up. Adds 1 << (n-1) as a rounding bias before shifting, so values exactly at the half-LSB boundary round up rather than truncating. Equivalent to dividing by 2^n in Q15 fixed-point with correct rounding.
Parameters:
aInput array (int16_t).a_lenNumber of elements in a.outOutput array (int16_t), same length as a.nShift count (non-negative integer).
>>> from doppler.arith import shr_q15
>>> import numpy as np
>>> a = np.array([100, 101, 102, -100], dtype=np.int16)
>>> shr_q15(a, 2).tolist()
[25, 25, 26, -25]
function shr_q8¶
Elementwise arithmetic right shift of a Q8 array with round-half-up. Adds 1 << (n-1) as a rounding bias before shifting, matching the rounding convention of shr_q15 at 8-bit precision.
Parameters:
aInput array (int8_t).a_lenNumber of elements in a.outOutput array (int8_t), same length as a.nShift count (non-negative integer).
>>> from doppler.arith import shr_q8
>>> import numpy as np
>>> a = np.array([10, 11, 12, -10], dtype=np.int8)
>>> shr_q8(a, 2).tolist()
[3, 3, 3, -2]
function sub_q15¶
Elementwise saturating subtract of two Q15 arrays. Computes out[i] = sat16(a[i] -b[i] ) for i in[0, min(len(a), len(b))) . The intermediate difference is computed as int32_t to detect overflow before clamping, preserving the correct sign at the saturation boundary.
Parameters:
aMinuend array (int16_t).a_lenNumber of elements in a.bSubtrahend array (int16_t), same length as a.b_lenNumber of elements in b.outOutput array (int16_t), length min(a_len, b_len).
>>> from doppler.arith import sub_q15
>>> import numpy as np
>>> a = np.array([100, 0, -32768], dtype=np.int16)
>>> b = np.array([50, 0, 10], dtype=np.int16)
>>> sub_q15(a, b).tolist()
[50, 0, -32768]
function sub_q8¶
Elementwise saturating subtract of two Q8 arrays. Computes out[i] = sat8(a[i] -b[i] ) for i in[0, min(len(a), len(b))) . The intermediate difference is computed as int16_t so overflow is detected before clamping.
Parameters:
aMinuend array (int8_t).a_lenNumber of elements in a.bSubtrahend array (int8_t), same length as a.b_lenNumber of elements in b.outOutput array (int8_t), length min(a_len, b_len).
>>> from doppler.arith import sub_q8
>>> import numpy as np
>>> a = np.array([50, 0, -128], dtype=np.int8)
>>> b = np.array([30, 0, 10], dtype=np.int8)
>>> sub_q8(a, b).tolist()
[20, 0, -128]
Public Static Functions Documentation¶
function sat16¶
function sat8¶
The documentation for this class was generated from the following file native/inc/arith/arith_core.h