The form of these is:
mlib: <standard math library or built in signature>
C: <C signature>
C++: <C++ signature>
<optional description>
mlib: x+y
C: inline int pd_add(pseudo_double x, pseudo_double y);
C++: inline PseudoDouble PseudoDouble::operator+(const PseudoDouble x) const;
mlib: x-y
C: inline int pd_sub(pseudo_double x, pseudo_double y);
C++: inline PseudoDouble PseudoDouble::operator-(const PseudoDouble x) const;
mlib: x*y
C: inline int pd_mult(pseudo_double x, pseudo_double y);
C++: inline PseudoDouble PseudoDouble::operator*(const PseudoDouble x) const;
mlib: x/y
C: inline int pd_div(pseudo_double x, pseudo_double y);
C++: inline PseudoDouble PseudoDouble::operator/(const PseudoDouble x) const;
mlib: -x
C: inline int pd_neg(pseudo_double x);
C++: inline PseudoDouble PseudoDouble::operator-() const;
mlib: x==y
C: (use integer x==y)
C++: inline bool PseudoDouble::operator==(const PseudoDouble x) const;
mlib: x!=y
C: (use integer x!=y)
C++: inline bool PseudoDouble::operator!=(const PseudoDouble x) const;
mlib: x>y
C: inline int pd_gt(pseudo_double x, pseudo_double y);
C++: inline bool PseudoDouble::operator>(const PseudoDouble x) const;
mlib: x>=y
C: inline int pd_gte(pseudo_double x, pseudo_double y);
C++: inline bool PseudoDouble::operator>=(const PseudoDouble x) const;
mlib: x<y
C: (use pd_gt with reversed arguments)
C++ inline bool PseudoDouble::operator<(const PseudoDouble x) const;
mlib: x<=y
C: (use pd_gte with reversed arguments)
C++: inline bool PseudoDouble::operator<=(const PseudoDouble x) const;
If using pseudo_double_i, == and != can be used directly, as long as both sides are pseudo_double_i.
C: inline bool pd_gt_zero(pseudo_double x)
C++: inline bool PseudoDouble::gt_zero() const;
C: inline bool pd_gte_zero(pseudo_double x)
C++: inline bool PseudoDouble::gte_zero() const;
C: inline bool pd_lt_zero(pseudo_double x)
C++: inline bool PseudoDouble::lt_zero() const;
C: inline bool pd_lte_zero(pseudo_double x)
C++: inline bool PseudoDouble::lte_zero() const;
C: inline bool pd_eq_zero(pseudo_double x)
C++: inline bool PseudoDouble::eq_zero() const;
C: inline bool pd_neq_zero(pseudo_double x)
C++: inline bool PseudoDouble::neq_zero() const;
If using pseudo_double_i, just do a straight integer comparison with zero (note that does not work with any other number)
C: pseudo_double double_to_pd(double d);
C++: inline PseudoDouble(double f);
C: pseudo_double int64_to_pd(int64_t d);
C++: inline PseudoDouble(int16_t f);
C++: inline PseudoDouble(int32_t f);
C++: inline PseudoDouble(int64_t f);
C: pseudo_double uint64_to_pd(uint64_t d);
C++: inline PseudoDouble(uint16_t f);
C++: inline PseudoDouble(uint32_t f);
C++: inline PseudoDouble(uint64_t f);
C: double pd_to_double(pseudo_double d);
C++: inline operator double() const {return pd_to_double(val);}
C: int64_t pd_to_int64(pseudo_double d);
C++: inline operator PseudoDouble::int16_t() const;
C++: inline operator PseudoDouble::int32_t() const;
C++: inline operator PseudoDouble::int64_t() const;
C: uint64_t pd_to_uint64(pseudo_double d);
C++: inline operator PseudoDouble::uint16_t() const;
C++: inline operator PseudoDouble::uint32_t() const;
C++: inline operator PseudoDouble::uint64_t() const;
C: pseudo_double sint64fixed2_to_pd(int64_t d, int32_t e);
C++: int64_t pd_to_sint64fixed2(pseudo_double d, int32_t e);
C++: inline pseudo_double sint64fixed10_to_pd(int64_t d, int32_t e);
mlib: floor(x)
C: pseudo_double pd_floor(pseudo_double x);
C++: PseudoDouble floor(const PseudoDouble x);
mlib: ceil(x)
C: pseudo_double pd_ceil(pseudo_double x);
C++: PseudoDouble ceil(const PseudoDouble x);
mlib: round(x)
C: pseudo_double pd_round(pseudo_double x);
C++: PseudoDouble round(const PseudoDouble x);
Returns the integral value that is nearest to x, with halfway cases rounded away from zero.
mlib: ldexp(x,y)
C: inline pseudo_double pd_ldexp(pseudo_double x, int y);
C++: PseudoDouble ldexp(const PseudoDouble x, int y);
mlib: std::max(x,y) (c++ only)
C: inline pseudo_double pd_max(pseudo_double x, pseudo_double y);
C++: PseudoDouble max(const PseudoDouble x, PseudoDouble y);
mlib: std::min(x,y) (c++ only)
C: inline pseudo_double pd_min(pseudo_double x, pseudo_double y);
C++: PseudoDouble min(const PseudoDouble x, PseudoDouble y);
mlib: sqrt(x)
C: pseudo_double pd_sqrt(pseudo_double x);
C++: PseudoDouble sqrt(const PseudoDouble x);
mlib: 1.0/sqrt(x)
C: pseudo_double pd_inv_sqrt(pseudo_double x);
C++: PseudoDouble inv_sqrt(const PseudoDouble x);
This is faster than sqrt and useful for normalizing
PseudoDouble PD_create_fixed10(int64_t x, int32_t e);
PseudoDouble PD_create_fixed2(int64_t x, int32_t e);
int64_t PD_get_fixed2(PseudoDouble x, int32_t e);
C++: inline pseudo_double PseudoDouble::get_internal() const;
C++: inline void PseudoDouble::set_internal(pseudo_double f);
The base fuctions are pd_exp2 and pd_log2, so:
- pd_exp2(
$n$ ) is exactly$2^n$ (subject to no overflow) - pd_log2(
$2^n$ ) is exactly$n$
mlib: exp2(x)
C: pseudo_double pd_exp2(pseudo_double x);
C++: PseudoDouble exp2(const PseudoDouble x);
mlib: log2(x)
C: pseudo_double pd_log2(pseudo_double x);
C++: PseudoDouble log2(const PseudoDouble x);
mlib: exp(x)
C: pseudo_double pd_exp(pseudo_double x);
C++: PseudoDouble exp(const PseudoDouble x);
mlib: log(x)
C: pseudo_double pd_log(pseudo_double x);
C++: PseudoDouble log(const PseudoDouble x);
mlib: log10(x)
C: pseudo_double pd_log10(pseudo_double x);
C++: PseudoDouble log10(const PseudoDouble x);
mlib: pow(x,y)
C: pseudo_double pd_pow(pseudo_double x, pseudo_double y);
C++: PseudoDouble pow(const PseudoDouble x, const PseudoDouble y);
Becasuse this is aimed at games rather than scientific applications, the base trigonometry functions use revolutions (turns). A revolution is
The following identities are exactly true for all integer
- pd_sin_rev(
$\frac{n}{2}$ ) = 0 - pd_sin_rev(
$n+\frac{1}{4}$ ) = 1 - pd_sin_rev(
$n+\frac{3}{4}$ ) = -1 - pd_cos_rev(
$\frac{n}{2}+\frac{1}{4}$ ) = 0 - pd_cos_rev(
$n$ ) = 1 - pd_cos_rev(
$n+\frac{1}{2}$ ) = -1 - pd_atan2_rev(0,0) = 0
- pd_atan2_rev(0,x) = 0
- pd_atan2_rev(x,x) =
$\frac{1}{8}$ - pd_atan2_rev(x,0) =
$\frac{1}{4}$ - pd_atan2_rev(x,-x) =
$\frac{3}{8}$ - pd_atan2_rev(0,-x) =
$\frac{1}{2}$ - pd_atan2_rev(-x,-x)=
$\frac{5}{8}$ - pd_atan2_rev(-x,0) =
$\frac{3}{4}$ - pd_atan2_rev(-x,x) =
$\frac{7}{8}$
mlib: sin(x*(2.0*M_PI))
C: pseudo_double pd_sin_rev(pseudo_double x);
C++: PseudoDouble sin_rev(const PseudoDouble x);
mlib: cos(x*(2.0*M_PI))
C: pseudo_double pd_cos_rev(pseudo_double x);
C++: PseudoDouble cos_rev(const PseudoDouble x);
mlib: atan2(y,x)/(2.0*M_PI)
C: pseudo_double pd_atan2_rev(pseudo_double y, pseudo_double x);
C++: PseudoDouble atan2_rev(const PseudoDouble y, const PseudoDouble x);
mlib: sin(x)
C: pseudo_double pd_sin(pseudo_double x);
C++: PseudoDouble sin(const PseudoDouble x);
mlib: cos(x)
C: pseudo_double pd_cos(pseudo_double x);
C++: PseudoDouble cos(const PseudoDouble x);
mlib: atan2(y,x)
C: pseudo_double pd_atan2(pseudo_double y, pseudo_double x);
C++: PseudoDouble atan2(const PseudoDouble y, const PseudoDouble x);
C/C++: inline uint64_t multu64hi(uint64_t x,uint64_t y);
calculate (x*y)>>64
Useful if x,y and result are considered 0.64 fixed unsigned ints
C/C++: inline int64_t mults64hi(int64_t x,int64_t y);
calculate (x*y)>>64
Useful if x,y and result are considered 0.64 fixed signed ints
C/C++: uint64_t inv_sqrt64_fixed(uint64_t x);
calculate 1/sqrt(x)
x is a 2.62 unsigned fixed in the range (1,4)
result is 1.63 unsigned fixed in the range (0.5,1)
C/C++: uint64_t exp2_64_fixed(uint64_t x);
calculate 2^x
x is a 0.64 unsigned fixed in the range [0,1)
result is 2.62 unsigned fixed in the range [1,2)
C/C++: uint64_t log2_64_fixed(uint64_t x);
calculate ln2(x+1)
x is a 1.63 unsigned fixed in the range [0,1)
result is 1.63 unsigned fixed in the range [0,1)
C/C++: uint64_t sin_rev_64_fixed(uint64_t x);
calculate sin(x)
x is a 0.64 unsigned fixed in the range [0,1/4] in revolutions
result is 2.62 unsigned fixed in the range [0,1]
C/C++: uint64_t atan_rev_64_fixed(uint64_t x);
calculate atan(x)
x is a 2.62 unsigned fixed in the range [0,1]
result is (-1).65 unsigned fixed in the range [0,1/8] in revolutions
(-1).65 means the values 0x0000000000000000..0xFFFFFFFFFFFFFFFF maps to 0..1/2