std1.0.0-beta-7 SafeC docs

Source dsp/fixed.sc

View in the repository

#pragma once
#include <std/dsp/fixed.h>

namespace std {

newtype Fixed = int;

inline const Fixed fixed_from_int(int x) {
    return (Fixed)(x << 24);
}

inline const Fixed fixed_from_float(double f) {
    // Multiply by 2^24 and cast to int to get Q8.24 representation.
    int raw = (int)(f * 16777216.0);
    return (Fixed)raw;
}

inline const int fixed_to_int(Fixed x) {
    // Arithmetic right shift drops the fractional bits.
    return (int)x >> 24;
}

inline const double fixed_to_float(Fixed x) {
    return (double)(int)x / 16777216.0;
}

inline const Fixed fixed_add(Fixed a, Fixed b) {
    return (Fixed)((int)a + (int)b);
}

inline const Fixed fixed_sub(Fixed a, Fixed b) {
    return (Fixed)((int)a - (int)b);
}

inline const Fixed fixed_mul(Fixed a, Fixed b) {
    // Promote to 64-bit to avoid intermediate overflow.
    long long product = (long long)(int)a * (long long)(int)b;
    return (Fixed)(int)(product >> 24);
}

inline const Fixed fixed_div(Fixed a, Fixed b) {
    // Shift a up by 24 before dividing so the result stays in Q8.24.
    long long num = (long long)(int)a << 24;
    return (Fixed)(int)(num / (long long)(int)b);
}

inline const Fixed fixed_abs(Fixed x) {
    int raw = (int)x;
    if (raw < 0) {
        return (Fixed)(-raw);
    }
    return (Fixed)raw;
}

inline const Fixed fixed_neg(Fixed x) {
    return (Fixed)(-(int)x);
}

// Newton-Raphson integer square root on Q8.24.
// We compute sqrt(x) in Q8.24 by treating the underlying int as a Q32 value
// and performing 4 Newton iterations: r = (r + x/r) / 2.
inline const Fixed fixed_sqrt(Fixed x) {
    if ((int)x <= 0) {
        return (Fixed)0;
    }
    // sqrt(x) in Q8.24 is sqrt(raw / 2^24) * 2^24 = sqrt(raw * 2^24): take
    // the exact integer square root of the widened value directly (raw <
    // 2^31, so raw << 24 < 2^55 fits). Bit-by-bit method: 28 fixed
    // iterations, exact floor result for every input — no initial-guess
    // dependence like Newton's method, which needs input-dependent
    // iteration counts to converge.
    unsigned long long v = (unsigned long long)(long long)(int)x << 24;
    unsigned long long res = 0ULL;
    unsigned long long bit = 1ULL << 54;
    while (bit > v) { bit = bit >> 2; }
    while (bit != 0ULL) {
        if (v >= res + bit) {
            v = v - (res + bit);
            res = (res >> 1) + bit;
        } else {
            res = res >> 1;
        }
        bit = bit >> 2;
    }
    return (Fixed)(int)res;
}

} // namespace std