blob: 31e04b68b1258524e44912b46c507cce0a2053cf [file] [log] [blame]
//========================================================================
//
// FixedPoint.cc
//
// Fixed point type, with C++ operators.
//
// Copyright 2004 Glyph & Cog, LLC
//
//========================================================================
//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================
#include <config.h>
#ifdef USE_FIXEDPOINT
#include "FixedPoint.h"
#define ln2 ((FixedPoint)0.69314718)
#define ln2 ((FixedPoint)0.69314718)
FixedPoint FixedPoint::sqrt(FixedPoint x) {
FixedPoint y0, y1, z;
if (x.val <= 0) {
y1.val = 0;
} else {
y1.val = x.val == 1 ? 2 : x.val >> 1;
do {
y0.val = y1.val;
z = x / y0;
y1.val = (y0.val + z.val) >> 1;
} while (::abs(y0.val - y1.val) > 1);
}
return y1;
}
FixedPoint FixedPoint::pow(FixedPoint x, FixedPoint y) {
FixedPoint t, t2, lnx0, lnx, z0, z;
int d, n, i;
if (y.val <= 0) {
z.val = 0;
} else {
// y * ln(x)
t = (x - 1) / (x + 1);
t2 = t * t;
d = 1;
lnx = 0;
do {
lnx0 = lnx;
lnx += t / d;
t *= t2;
d += 2;
} while (::abs(lnx.val - lnx0.val) > 2);
lnx.val <<= 1;
t = y * lnx;
// exp(y * ln(x))
n = floor(t / ln2);
t -= ln2 * n;
t2 = t;
d = 1;
i = 1;
z = 1;
do {
z0 = z;
z += t2 / d;
t2 *= t;
++i;
d *= i;
} while (::abs(z.val - z0.val) > 2 && d < (1 << fixptShift));
if (n >= 0) {
z.val <<= n;
} else if (n < 0) {
z.val >>= -n;
}
}
return z;
}
int FixedPoint::mul(int x, int y) {
FixPtInt64 z;
z = ((FixPtInt64)x * y) >> fixptShift;
if (z > 0x7fffffffLL) {
return 0x7fffffff;
} else if (z < -0x80000000LL) {
return 0x80000000;
} else {
return (int)z;
}
}
int FixedPoint::div(int x, int y) {
FixPtInt64 z;
z = ((FixPtInt64)x << fixptShift) / y;
if (z > 0x7fffffffLL) {
return 0x7fffffff;
} else if (z < -0x80000000LL) {
return 0x80000000;
} else {
return (int)z;
}
}
bool FixedPoint::divCheck(FixedPoint x, FixedPoint y, FixedPoint *result) {
FixPtInt64 z;
z = ((FixPtInt64)x.val << fixptShift) / y.val;
if ((z == 0 && x != 0) ||
z >= ((FixPtInt64)1 << 31) || z < -((FixPtInt64)1 << 31)) {
return false;
}
result->val = z;
return true;
}
bool FixedPoint::checkDet(FixedPoint m11, FixedPoint m12,
FixedPoint m21, FixedPoint m22,
FixedPoint epsilon) {
FixPtInt64 det, e;
det = (FixPtInt64)m11.val * (FixPtInt64)m22.val
- (FixPtInt64)m12.val * (FixPtInt64)m21.val;
e = (FixPtInt64)epsilon.val << fixptShift;
// NB: this comparison has to be >= not > because epsilon can be
// truncated to zero as a fixed point value.
return det >= e || det <= -e;
}
#endif // USE_FIXEDPOINT