1075 lines
22 KiB
C++
1075 lines
22 KiB
C++
// Copyright 2007 David Hilvert <dhilvert@auricle.dyndns.org>,
|
|
// <dhilvert@ugcs.caltech.edu>
|
|
|
|
/* This file is part of the Anti-Lamenessing Engine.
|
|
|
|
The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with the Anti-Lamenessing Engine; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#ifndef __ale_fixed_h__
|
|
#define __ale_fixed_h__
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "ale_math.h"
|
|
|
|
#define FIXED16 4
|
|
#define FIXED32 5
|
|
|
|
#define DEBUG_FIXED_POINT 0
|
|
|
|
/*
|
|
* Define a fixed point data type.
|
|
*/
|
|
|
|
class ale_fixed_16 {
|
|
public:
|
|
typedef short bits_t;
|
|
typedef int mulbits_t;
|
|
static bits_t posinf() {
|
|
return 32767;
|
|
}
|
|
static bits_t neginf() {
|
|
return -32766;
|
|
}
|
|
static bits_t nan() {
|
|
return -32767;
|
|
}
|
|
static bits_t rint(double d) {
|
|
return (bits_t) lrint(d);
|
|
}
|
|
};
|
|
|
|
class ale_fixed_16_calc {
|
|
public:
|
|
typedef int bits_t;
|
|
typedef int mulbits_t;
|
|
static bits_t posinf() {
|
|
return 2147483647;
|
|
}
|
|
static bits_t neginf() {
|
|
return -2147483646;
|
|
}
|
|
static bits_t nan() {
|
|
return -2147483647;
|
|
}
|
|
static bits_t rint(double d) {
|
|
return (bits_t) lrint(d);
|
|
}
|
|
};
|
|
|
|
#if ALE_COLORS == FIXED16
|
|
class ale_fixed_16_accum {
|
|
public:
|
|
typedef int bits_t;
|
|
typedef long long mulbits_t;
|
|
static bits_t posinf() {
|
|
return 2147483647;
|
|
}
|
|
static bits_t neginf() {
|
|
return -2147483646;
|
|
}
|
|
static bits_t nan() {
|
|
return -2147483647;
|
|
}
|
|
static bits_t rint(double d) {
|
|
return (bits_t) lrint(d);
|
|
}
|
|
};
|
|
#endif
|
|
|
|
#if ALE_COLORS == FIXED32 || ALE_COORDINATES == FIXED32
|
|
class ale_fixed_32 {
|
|
public:
|
|
typedef int bits_t;
|
|
typedef long long mulbits_t;
|
|
static bits_t posinf() {
|
|
return 2147483647;
|
|
}
|
|
static bits_t neginf() {
|
|
return -2147483646;
|
|
}
|
|
static bits_t nan() {
|
|
return -2147483647;
|
|
}
|
|
static bits_t rint(double d) {
|
|
return (bits_t) lrint(d);
|
|
}
|
|
};
|
|
#endif
|
|
|
|
#if ALE_COLORS == FIXED32
|
|
class ale_fixed_32_accum {
|
|
public:
|
|
typedef long long bits_t;
|
|
typedef long long mulbits_t;
|
|
static bits_t posinf() {
|
|
return 9223372036854775807LL;
|
|
}
|
|
static bits_t neginf() {
|
|
return -9223372036854775806LL;
|
|
}
|
|
static bits_t nan() {
|
|
return -9223372036854775807LL;
|
|
}
|
|
static bits_t rint(double d) {
|
|
return (bits_t) llrint(d);
|
|
}
|
|
};
|
|
#endif
|
|
|
|
#define ALE_FIXED_NAN (fixed_type::nan())
|
|
#define ALE_FIXED_POSINF (fixed_type::posinf())
|
|
#define ALE_FIXED_NEGINF (fixed_type::neginf())
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
class ale_fixed {
|
|
static int casting_disabled;
|
|
|
|
public:
|
|
|
|
typedef typename fixed_type::bits_t bits_t;
|
|
typedef typename fixed_type::mulbits_t mulbits_t;
|
|
|
|
bits_t bits;
|
|
|
|
/*
|
|
* Bit-conversion facilities.
|
|
*/
|
|
|
|
static ale_fixed bits_to_fixed(bits_t b) {
|
|
ale_fixed result;
|
|
result.bits = b;
|
|
return result;
|
|
}
|
|
|
|
static bits_t fixed_to_bits(ale_fixed f) {
|
|
|
|
if (f.bits >= 1 << N)
|
|
return ((1 << N) - 1);
|
|
|
|
return f.bits;
|
|
}
|
|
|
|
|
|
/*
|
|
* Constructors.
|
|
*/
|
|
ale_fixed() {
|
|
bits = 0;
|
|
}
|
|
|
|
ale_fixed(const ale_fixed &f) {
|
|
bits = f.bits;
|
|
}
|
|
|
|
ale_fixed& operator=(const ale_fixed &f) {
|
|
bits = f.bits;
|
|
|
|
return (*this);
|
|
}
|
|
|
|
/*
|
|
* Disable casting
|
|
*/
|
|
|
|
static void disable_casting() {
|
|
casting_disabled = 1;
|
|
}
|
|
|
|
/*
|
|
* Enable casting
|
|
*/
|
|
|
|
static void enable_casting() {
|
|
casting_disabled = 0;
|
|
}
|
|
|
|
/*
|
|
* Casting status.
|
|
*/
|
|
|
|
static int casting_status() {
|
|
return !casting_disabled;
|
|
}
|
|
|
|
/*
|
|
* Cast to ordinary numbers
|
|
*/
|
|
|
|
operator double() const {
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
assert(!casting_disabled);
|
|
if (bits == ALE_FIXED_NAN) {
|
|
double zero = 0;
|
|
double nan = zero / zero;
|
|
assert (isnan(nan));
|
|
return nan;
|
|
} else if (bits == ALE_FIXED_NEGINF) {
|
|
double zero = 0;
|
|
double negone = -1;
|
|
double neginf = negone / zero;
|
|
assert (isinf(neginf));
|
|
assert (neginf < 0);
|
|
return neginf;
|
|
} else if (bits == ALE_FIXED_POSINF) {
|
|
double zero = 0;
|
|
double posone = +1;
|
|
double posinf = posone / zero;
|
|
assert (isinf(posinf));
|
|
assert (posinf > 0);
|
|
return posinf;
|
|
}
|
|
#endif
|
|
|
|
return (((double) bits) / (1 << N));
|
|
}
|
|
|
|
operator float() const {
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
assert(!casting_disabled);
|
|
if (bits == ALE_FIXED_NAN) {
|
|
float zero = 0;
|
|
float nan = zero / zero;
|
|
assert (isnan(nan));
|
|
return nan;
|
|
} else if (bits == ALE_FIXED_NEGINF) {
|
|
float zero = 0;
|
|
float negone = -1;
|
|
float neginf = negone / zero;
|
|
assert (isinf(neginf));
|
|
assert (neginf < 0);
|
|
return neginf;
|
|
} else if (bits == ALE_FIXED_POSINF) {
|
|
float zero = 0;
|
|
float posone = +1;
|
|
float posinf = posone / zero;
|
|
assert (isinf(posinf));
|
|
assert (posinf > 0);
|
|
return posinf;
|
|
}
|
|
#endif
|
|
|
|
return (((float) bits) / (1 << N));
|
|
}
|
|
|
|
operator int() const {
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
assert (bits != ALE_FIXED_NAN);
|
|
assert (bits != ALE_FIXED_POSINF);
|
|
assert (bits != ALE_FIXED_NEGINF);
|
|
#endif
|
|
|
|
return bits / (1 << N);
|
|
}
|
|
|
|
operator unsigned int() const {
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
assert (bits != ALE_FIXED_NAN);
|
|
assert (bits != ALE_FIXED_POSINF);
|
|
assert (bits != ALE_FIXED_NEGINF);
|
|
assert (bits >= 0);
|
|
#endif
|
|
|
|
return (unsigned int) operator int();
|
|
}
|
|
|
|
#if 0
|
|
template<class fixed_type_2, unsigned int M>
|
|
operator ale_fixed<fixed_type_2, M>() const {
|
|
ale_fixed<fixed_type_2, M> result;
|
|
|
|
if (bits == ALE_FIXED_NAN) {
|
|
result.bits = fixed_type_2::nan();
|
|
return result;
|
|
}
|
|
|
|
if (bits == ALE_FIXED_POSINF) {
|
|
result.bits = fixed_type_2::posinf();
|
|
return result;
|
|
}
|
|
|
|
if (bits == ALE_FIXED_NEGINF) {
|
|
result.bits = fixed_type_2::neginf();
|
|
return result;
|
|
}
|
|
|
|
if (sizeof(ale_fixed<fixed_type_2,M>) > sizeof(ale_fixed<fixed_type,N>)) {
|
|
typedef typename fixed_type_2::bits_t bits_t_calc;
|
|
|
|
bits_t_calc type_result;
|
|
|
|
if (M >= N)
|
|
type_result = bits << (bits_t_calc) ((int) M - (int) N);
|
|
else
|
|
type_result = bits / ((bits_t_calc) 1 << (bits_t_calc) ((int) N - (int) M));
|
|
|
|
result.bits = type_result;
|
|
|
|
} else {
|
|
typedef bits_t bits_t_calc;
|
|
|
|
bits_t_calc type_result;
|
|
|
|
if (M >= N)
|
|
type_result = bits << (bits_t_calc) ((int) M - (int) N);
|
|
else
|
|
type_result = bits / ((bits_t_calc) 1 << (bits_t_calc) ((int) N - (int) M));
|
|
|
|
if (type_result > fixed_type_2::posinf())
|
|
result.bits = fixed_type_2::posinf();
|
|
else if (type_result < fixed_type_2::neginf())
|
|
result.bits = fixed_type_2::neginf();
|
|
else
|
|
result.bits = type_result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Cast from ordinary numbers
|
|
*/
|
|
|
|
template<class fixed_type_2, unsigned int M>
|
|
ale_fixed(const ale_fixed<fixed_type_2,M> &d) {
|
|
|
|
/*
|
|
* XXX: this shouldn't be necessary.
|
|
*/
|
|
|
|
bits = 0;
|
|
|
|
if (d.bits == fixed_type_2::nan()) {
|
|
bits = ALE_FIXED_NAN;
|
|
return;
|
|
}
|
|
|
|
if (bits == fixed_type_2::posinf()) {
|
|
bits = ALE_FIXED_POSINF;
|
|
return;
|
|
}
|
|
|
|
if (bits == fixed_type_2::neginf()) {
|
|
bits = ALE_FIXED_NEGINF;
|
|
return;
|
|
}
|
|
|
|
if (sizeof(ale_fixed<fixed_type,N>) > sizeof(ale_fixed<fixed_type_2,M>)) {
|
|
if (N >= M)
|
|
bits = d.bits << (bits_t) ((int) N - (int) M);
|
|
else
|
|
bits = d.bits / ((bits_t) 1 << (bits_t) ((int) M - (int) N));
|
|
} else {
|
|
typedef typename ale_fixed<fixed_type_2,M>::bits_t bits_t_calc;
|
|
|
|
bits_t_calc type_result;
|
|
|
|
if (N >= M)
|
|
type_result = d.bits << (bits_t_calc) ((int) N - (int) M);
|
|
else
|
|
type_result = d.bits / ((bits_t_calc) 1 << (bits_t_calc) ((int) M - (int) N));
|
|
|
|
if (type_result > ALE_FIXED_POSINF)
|
|
bits = ALE_FIXED_POSINF;
|
|
else if (type_result < ALE_FIXED_NEGINF)
|
|
bits = ALE_FIXED_NEGINF;
|
|
else
|
|
bits = type_result;
|
|
}
|
|
}
|
|
|
|
ale_fixed(double d) {
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed due to a tendency to trigger unpredictably.
|
|
*/
|
|
assert(!casting_disabled);
|
|
#endif
|
|
|
|
if (isnan(d)) {
|
|
bits = ALE_FIXED_NAN;
|
|
} else if (isinf(d) && d > 0) {
|
|
bits = ALE_FIXED_POSINF;
|
|
} else if (isinf(d) && d < 0) {
|
|
bits = ALE_FIXED_NEGINF;
|
|
} else {
|
|
bits = (bits_t) fixed_type::rint(d * (1 << N));
|
|
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
assert((double) *this > (d - (double) 1 / (1 << N)));
|
|
assert((double) *this < (d + (double) 1 / (1 << N)));
|
|
|
|
assert(bits < ALE_FIXED_POSINF);
|
|
assert(bits > ALE_FIXED_NEGINF);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
ale_fixed(int d) {
|
|
bits = (bits_t) d << N;
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
assert((d >= 0 && bits >> N == d)
|
|
|| (d < 0 && (-bits) >> N == -d));
|
|
|
|
assert (bits < ALE_FIXED_POSINF);
|
|
assert (bits > ALE_FIXED_NEGINF);
|
|
#endif
|
|
}
|
|
|
|
ale_fixed(unsigned int d) {
|
|
bits = (bits_t) d << N;
|
|
|
|
assert((unsigned int) (bits >> N) == d);
|
|
|
|
assert (bits < ALE_FIXED_POSINF);
|
|
assert (bits > ALE_FIXED_NEGINF);
|
|
}
|
|
|
|
/*
|
|
* Operators.
|
|
*/
|
|
|
|
ale_fixed operator-() const {
|
|
|
|
ale_fixed result;
|
|
|
|
if (bits == ALE_FIXED_NAN || bits == 0)
|
|
return *this;
|
|
else if (bits == ALE_FIXED_POSINF)
|
|
result.bits = ALE_FIXED_NEGINF;
|
|
else if (bits == ALE_FIXED_NEGINF)
|
|
result.bits = ALE_FIXED_POSINF;
|
|
else
|
|
result.bits = -bits;
|
|
|
|
return result;
|
|
}
|
|
|
|
ale_fixed unexceptional_negation() const {
|
|
ale_fixed result;
|
|
|
|
result.bits = -bits;
|
|
|
|
return result;
|
|
}
|
|
|
|
ale_fixed operator+(ale_fixed f) const {
|
|
ale_fixed result;
|
|
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN
|
|
|| (bits == ALE_FIXED_POSINF && f.bits == ALE_FIXED_NEGINF)
|
|
|| (bits == ALE_FIXED_NEGINF && f.bits == ALE_FIXED_POSINF)) {
|
|
result.bits = ALE_FIXED_NAN;
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
bits_t bits_result = bits + f.bits;
|
|
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
if (bits_result >= ALE_FIXED_POSINF
|
|
|| bits == ALE_FIXED_POSINF || f.bits == ALE_FIXED_POSINF
|
|
|| bits > 0 && f.bits > 0 && bits_result < 0) {
|
|
result.bits = ALE_FIXED_POSINF;
|
|
return result;
|
|
} else if (bits_result <= ALE_FIXED_NEGINF
|
|
|| bits == ALE_FIXED_NEGINF || f.bits == ALE_FIXED_NEGINF
|
|
|| bits < 0 && f.bits < 0 && bits_result > 0) {
|
|
result.bits = ALE_FIXED_NEGINF;
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
result.bits = bits_result;
|
|
|
|
return result;
|
|
}
|
|
|
|
ale_fixed operator+(int i) const {
|
|
return operator+(ale_fixed(i));
|
|
}
|
|
|
|
ale_fixed operator+(unsigned int i) const {
|
|
return operator+(ale_fixed(i));
|
|
}
|
|
|
|
ale_fixed operator-(ale_fixed f) const {
|
|
ale_fixed result;
|
|
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN
|
|
|| (bits == ALE_FIXED_POSINF && f.bits == ALE_FIXED_POSINF)
|
|
|| (bits == ALE_FIXED_NEGINF && f.bits == ALE_FIXED_NEGINF)) {
|
|
result.bits = ALE_FIXED_NAN;
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
bits_t bits_result = bits - f.bits;
|
|
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
if (bits_result >= ALE_FIXED_POSINF
|
|
|| bits == ALE_FIXED_POSINF || f.bits == ALE_FIXED_NEGINF
|
|
|| bits > 0 && f.bits < 0 && bits_result < 0) {
|
|
result.bits = ALE_FIXED_POSINF;
|
|
return result;
|
|
} else if (bits_result <= ALE_FIXED_NEGINF
|
|
|| bits == ALE_FIXED_NEGINF || f.bits == ALE_FIXED_POSINF
|
|
|| bits < 0 && f.bits > 0 && bits_result > 0) {
|
|
result.bits = ALE_FIXED_NEGINF;
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
result.bits = bits_result;
|
|
|
|
return result;
|
|
}
|
|
|
|
ale_fixed operator-(int i) const {
|
|
return operator-(ale_fixed(i));
|
|
}
|
|
|
|
ale_fixed operator-(unsigned int i) const {
|
|
return operator-(ale_fixed(i));
|
|
}
|
|
|
|
ale_fixed operator*(ale_fixed f) const {
|
|
ale_fixed result;
|
|
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN) {
|
|
result.bits = ALE_FIXED_NAN;
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
|
|
mulbits_t mul_result = ((mulbits_t) bits * (mulbits_t) f.bits) / (1 << N);
|
|
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
if (mul_result > (mulbits_t) ALE_FIXED_POSINF
|
|
|| mul_result < (mulbits_t) ALE_FIXED_NEGINF
|
|
|| bits == ALE_FIXED_POSINF || f.bits == ALE_FIXED_POSINF
|
|
|| bits == ALE_FIXED_NEGINF || f.bits == ALE_FIXED_NEGINF) {
|
|
if (mul_result > 0)
|
|
result.bits = ALE_FIXED_POSINF;
|
|
else if (mul_result < 0)
|
|
result.bits = ALE_FIXED_NEGINF;
|
|
else if (mul_result == 0)
|
|
result.bits = ALE_FIXED_NAN;
|
|
else
|
|
assert(0);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
result.bits = mul_result;
|
|
return result;
|
|
}
|
|
|
|
ale_fixed operator*(int i) const {
|
|
return operator*(ale_fixed(i));
|
|
}
|
|
|
|
ale_fixed operator*(unsigned int i) const {
|
|
return operator*(ale_fixed(i));
|
|
}
|
|
|
|
ale_fixed operator/(ale_fixed f) const {
|
|
ale_fixed result;
|
|
|
|
/*
|
|
* While this approach may not be suitable for all
|
|
* applications, it can be a convenient way to detect and
|
|
* manufacture non-finite values.
|
|
*/
|
|
if ((bits == 0 && f.bits == 0)
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
|| bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN
|
|
|| ((bits == ALE_FIXED_NEGINF || bits == ALE_FIXED_POSINF)
|
|
&& (f.bits == ALE_FIXED_NEGINF || f.bits == ALE_FIXED_POSINF))
|
|
#endif
|
|
) {
|
|
result.bits = ALE_FIXED_NAN;
|
|
return result;
|
|
} else if (f.bits == 0 && bits > 0) {
|
|
result.bits = ALE_FIXED_POSINF;
|
|
return result;
|
|
} else if (f.bits == 0 && bits < 0) {
|
|
result.bits = ALE_FIXED_NEGINF;
|
|
return result;
|
|
}
|
|
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
else if (f.bits == ALE_FIXED_POSINF || f.bits == ALE_FIXED_NEGINF) {
|
|
result.bits = 0;
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
mulbits_t div_result = ((mulbits_t) bits << N) / f.bits;
|
|
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
if (div_result > (mulbits_t) ALE_FIXED_POSINF) {
|
|
result.bits = ALE_FIXED_POSINF;
|
|
return result;
|
|
} else if (div_result < (mulbits_t) ALE_FIXED_NEGINF) {
|
|
result.bits = ALE_FIXED_NEGINF;
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
result.bits = (bits_t) div_result;
|
|
return result;
|
|
}
|
|
|
|
ale_fixed operator/(int i) const {
|
|
return operator/(ale_fixed(i));
|
|
}
|
|
|
|
ale_fixed operator/(unsigned int i) const {
|
|
return operator/(ale_fixed(i));
|
|
}
|
|
|
|
ale_fixed &operator+=(ale_fixed f) {
|
|
*this = *this + f;
|
|
return *this;
|
|
}
|
|
|
|
ale_fixed &operator-=(ale_fixed f) {
|
|
*this = *this - f;
|
|
return *this;
|
|
}
|
|
|
|
ale_fixed &operator*=(ale_fixed f) {
|
|
*this = *this * f;
|
|
return *this;
|
|
}
|
|
|
|
ale_fixed &operator/=(ale_fixed f) {
|
|
*this = *this / f;
|
|
return *this;
|
|
}
|
|
|
|
int operator!=(ale_fixed f) const {
|
|
if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN)
|
|
return 1;
|
|
|
|
if (bits == f.bits)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int operator==(ale_fixed f) const {
|
|
return !(operator!=(f));
|
|
}
|
|
|
|
int operator<=(ale_fixed f) const {
|
|
if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN)
|
|
return 0;
|
|
|
|
if (bits <= f.bits)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int operator>=(ale_fixed f) const {
|
|
if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN)
|
|
return 0;
|
|
|
|
if (bits >= f.bits)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int operator>(ale_fixed f) const {
|
|
if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN)
|
|
return 0;
|
|
|
|
if (bits > f.bits)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int operator<(ale_fixed f) const {
|
|
if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN)
|
|
return 0;
|
|
|
|
if (bits < f.bits)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int operator>=(int d) const {
|
|
return operator>=((ale_fixed) d);
|
|
}
|
|
|
|
int operator<=(int d) const {
|
|
return operator<=((ale_fixed) d);
|
|
}
|
|
|
|
int operator==(int d) const {
|
|
return operator==((ale_fixed) d);
|
|
}
|
|
|
|
int operator!=(int d) const {
|
|
return operator!=((ale_fixed) d);
|
|
}
|
|
|
|
int operator>(int d) const {
|
|
return operator>((ale_fixed) d);
|
|
}
|
|
|
|
int operator<(int d) const {
|
|
return operator<((ale_fixed) d);
|
|
}
|
|
|
|
int operator>=(double d) const {
|
|
return operator>=((ale_fixed) d);
|
|
}
|
|
|
|
int operator>=(float d) const {
|
|
return operator>=((ale_fixed) d);
|
|
}
|
|
|
|
int operator<=(double d) const {
|
|
return operator<=((ale_fixed) d);
|
|
}
|
|
|
|
int operator==(double d) const {
|
|
return operator==((ale_fixed) d);
|
|
}
|
|
|
|
int operator!=(double d) const {
|
|
return operator!=((ale_fixed) d);
|
|
}
|
|
|
|
int operator>(double d) const {
|
|
return operator>((ale_fixed) d);
|
|
}
|
|
|
|
int operator<(double d) const {
|
|
return operator<((ale_fixed) d);
|
|
}
|
|
|
|
int operator>=(unsigned int d) const {
|
|
return operator>=((ale_fixed) d);
|
|
}
|
|
|
|
int operator<=(unsigned int d) const {
|
|
return operator<=((ale_fixed) d);
|
|
}
|
|
|
|
int operator==(unsigned int d) const {
|
|
return operator==((ale_fixed) d);
|
|
}
|
|
|
|
int operator!=(unsigned int d) const {
|
|
return operator!=((ale_fixed) d);
|
|
}
|
|
|
|
int operator>(unsigned int d) const {
|
|
return operator>((ale_fixed) d);
|
|
}
|
|
|
|
int operator<(unsigned int d) const {
|
|
return operator<((ale_fixed) d);
|
|
}
|
|
|
|
};
|
|
|
|
#define ALE_FIXED_INCORPORATE_OPERATOR(return_value, op) \
|
|
template<class fixed_type, unsigned int N> \
|
|
return_value operator op(double a, const ale_fixed<fixed_type, N> &f) { \
|
|
ale_fixed<fixed_type, N> g(a); \
|
|
return g.operator op(f); \
|
|
} \
|
|
\
|
|
template<class fixed_type, unsigned int N> \
|
|
return_value operator op(int a, const ale_fixed<fixed_type, N> &f) { \
|
|
return (ale_fixed<fixed_type, N>) a op f; \
|
|
} \
|
|
\
|
|
template<class fixed_type, unsigned int N> \
|
|
return_value operator op(unsigned int a, const ale_fixed<fixed_type, N> &f) { \
|
|
return (ale_fixed<fixed_type, N>) a op f; \
|
|
} \
|
|
|
|
#define STDARGS ale_fixed<fixed_type,N>
|
|
|
|
ALE_FIXED_INCORPORATE_OPERATOR(STDARGS, +);
|
|
ALE_FIXED_INCORPORATE_OPERATOR(STDARGS, -);
|
|
ALE_FIXED_INCORPORATE_OPERATOR(STDARGS, *);
|
|
ALE_FIXED_INCORPORATE_OPERATOR(STDARGS, /);
|
|
ALE_FIXED_INCORPORATE_OPERATOR(int, <=);
|
|
ALE_FIXED_INCORPORATE_OPERATOR(int, >=);
|
|
ALE_FIXED_INCORPORATE_OPERATOR(int, <);
|
|
ALE_FIXED_INCORPORATE_OPERATOR(int, >);
|
|
ALE_FIXED_INCORPORATE_OPERATOR(int, !=);
|
|
ALE_FIXED_INCORPORATE_OPERATOR(int, ==);
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
ale_fixed<fixed_type, N> fabs(ale_fixed<fixed_type, N> f) {
|
|
if (f < ale_fixed<fixed_type, N>())
|
|
return -f;
|
|
return f;
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
ale_fixed<fixed_type, N> pow(ale_fixed<fixed_type, N> f, double d) {
|
|
return pow((double) f, (double) d);
|
|
}
|
|
|
|
/*
|
|
* sqrt() via the Babylonian method.
|
|
*
|
|
* http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
|
|
*/
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
ale_fixed<fixed_type, N> sqrt(ale_fixed<fixed_type, N> f) {
|
|
ale_fixed<fixed_type, N> guess = f;
|
|
|
|
typedef typename ale_fixed<fixed_type, N>::mulbits_t mulbits_t;
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
guess.bits >>= 1;
|
|
|
|
if (guess.bits <= 0)
|
|
return 0;
|
|
|
|
mulbits_t sf = (mulbits_t) f.bits << (N - 2);
|
|
guess.bits = guess.bits + sf / guess.bits;
|
|
}
|
|
|
|
return guess;
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
ale_fixed<fixed_type, N> pow(ale_fixed<fixed_type, N> f, ale_fixed<fixed_type, N> d) {
|
|
if (d == 2)
|
|
return f * f;
|
|
|
|
if (d == 1)
|
|
return f;
|
|
|
|
if (d == 0)
|
|
return ale_fixed<fixed_type,N>(1);
|
|
|
|
return pow((double) f, (double) d);
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
ale_fixed<fixed_type, N> pow(ale_fixed<fixed_type, N> f, int d) {
|
|
if (d == 2)
|
|
return f * f;
|
|
|
|
if (d == 1)
|
|
return f;
|
|
|
|
if (d == 0)
|
|
return ale_fixed<fixed_type, N>(1);
|
|
|
|
if (d > 1)
|
|
return pow(f, d / 2) * pow(f, d - d / 2);
|
|
|
|
if (d < 0)
|
|
return 1 / pow(f, -d);
|
|
|
|
assert(0);
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
ale_fixed<fixed_type, N> pow(ale_fixed<fixed_type, N> f, unsigned int d) {
|
|
if (d == 2)
|
|
return f * f;
|
|
|
|
if (d == 1)
|
|
return f;
|
|
|
|
if (d == 0)
|
|
return ale_fixed<fixed_type, N>(1);
|
|
|
|
return pow(f, d / 2) * pow(f, d - d / 2);
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
ale_fixed<fixed_type, N> floor(ale_fixed<fixed_type, N> f) {
|
|
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
if (N == 0
|
|
|| f.bits == ALE_FIXED_POSINF
|
|
|| f.bits == ALE_FIXED_NEGINF
|
|
|| f.bits == ALE_FIXED_NAN)
|
|
return f;
|
|
#endif
|
|
|
|
ale_fixed<fixed_type, N> result;
|
|
|
|
result.bits = (f.bits & ~((1 << N) - 1));
|
|
|
|
/*
|
|
* XXX: This isn't exactly right.
|
|
*/
|
|
if (f.bits < 0)
|
|
result.bits -= 1;
|
|
|
|
return result;
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
ale_fixed<fixed_type, N> lrintf(ale_fixed<fixed_type, N> f) {
|
|
|
|
#if DEBUG_FIXED_POINT
|
|
/*
|
|
* Removed for performance reasons.
|
|
*/
|
|
|
|
if (N == 0
|
|
|| f.bits == ALE_FIXED_POSINF
|
|
|| f.bits == ALE_FIXED_NEGINF
|
|
|| f.bits == ALE_FIXED_NAN)
|
|
return f;
|
|
#endif
|
|
|
|
ale_fixed<fixed_type, N> result = floor(f);
|
|
|
|
if (f.bits - result.bits >= (1 << N - 1))
|
|
result.bits += (1 << N);
|
|
|
|
return result;
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
ale_fixed<fixed_type, N> ceil(ale_fixed<fixed_type, N> f) {
|
|
return -floor(-f);
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
int ale_isinf(ale_fixed<fixed_type, N> f) {
|
|
return (f.bits == ALE_FIXED_NEGINF || f.bits == ALE_FIXED_POSINF);
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
int ale_isnan(ale_fixed<fixed_type, N> f) {
|
|
return (f.bits == ALE_FIXED_NAN);
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
int finite(ale_fixed<fixed_type, N> f) {
|
|
return (f.bits < ALE_FIXED_POSINF && f.bits > ALE_FIXED_NEGINF);
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N, unsigned int M>
|
|
ale_fixed<fixed_type, N> convert_precision(ale_fixed<fixed_type, M> m) {
|
|
|
|
/*
|
|
* XXX: Checks should be added that precision is not
|
|
* lost from most-significant bits.
|
|
*/
|
|
|
|
if (N != M)
|
|
assert (0);
|
|
|
|
ale_fixed<fixed_type, N> n;
|
|
|
|
n.bits = m.bits << (N - M);
|
|
|
|
return n;
|
|
}
|
|
|
|
template<class fixed_type, unsigned int N>
|
|
int ale_fixed<fixed_type, N>::casting_disabled = 0;
|
|
|
|
#undef FIXED16
|
|
#undef FIXED32
|
|
|
|
#endif
|