1415 lines
37 KiB
Diff
1415 lines
37 KiB
Diff
From 1111070c0a68d0a15d1488415392658a75662be4 Mon Sep 17 00:00:00 2001
|
|
From: Paul Ramsey <pramsey@cleverelephant.ca>
|
|
Date: Thu, 16 Apr 2020 15:31:11 -0700
|
|
Subject: [PATCH] Squashed commit of the following:
|
|
|
|
commit ab1b004af900354f907f9a5d31ec514c2547ada4
|
|
Author: Paul Ramsey <pramsey@cleverelephant.ca>
|
|
Date: Thu Apr 16 14:40:23 2020 -0700
|
|
|
|
remove ttmath in favour of DD
|
|
|
|
commit 472c1f9a12df1a4b9628f61c93594ee162382db4
|
|
Merge: 8ccf3bf8 312c085b
|
|
Author: Paul Ramsey <pramsey@cleverelephant.ca>
|
|
Date: Thu Apr 16 13:24:39 2020 -0700
|
|
|
|
Merge branch 'master' of https://git.osgeo.org/gitea/geos/geos into master-dd
|
|
|
|
commit 8ccf3bf874a2887b40afbaca57ee67b59b5eb40b
|
|
Author: Paul Ramsey <pramsey@cleverelephant.ca>
|
|
Date: Thu Apr 16 13:10:25 2020 -0700
|
|
|
|
add informational comment
|
|
|
|
commit 8fd12e02f060f8e35d36a162d81d1ef94da1b784
|
|
Author: Paul Ramsey <pramsey@cleverelephant.ca>
|
|
Date: Thu Apr 16 12:15:00 2020 -0700
|
|
|
|
add in all JTS unit tests for doubledouble calculations
|
|
|
|
commit e24af3ba8ce7eca76840164c2edd5e066bbebe28
|
|
Author: Paul Ramsey <pramsey@cleverelephant.ca>
|
|
Date: Wed Apr 15 13:47:56 2020 -0700
|
|
|
|
autotools build
|
|
|
|
commit cb5942a13c5113ae42108e0422fed9a34a465abf
|
|
Author: Paul Ramsey <pramsey@cleverelephant.ca>
|
|
Date: Wed Apr 15 13:31:28 2020 -0700
|
|
|
|
fix doxygen complaint?
|
|
|
|
commit 469037a4ca75b0f4df3638256c0fff2b61d37796
|
|
Author: Paul Ramsey <pramsey@cleverelephant.ca>
|
|
Date: Wed Apr 15 12:47:14 2020 -0700
|
|
|
|
change name of ifdef guard
|
|
|
|
commit 00559ec59b56a0ec6a0481b54f0ab597324d9439
|
|
Author: Paul Ramsey <pramsey@cleverelephant.ca>
|
|
Date: Wed Apr 15 12:40:50 2020 -0700
|
|
|
|
allow DD to swap in for ttmath
|
|
|
|
commit 75e70f7f28e751f26cc3db5b4964a86f3bae518f
|
|
Author: Paul Ramsey <pramsey@cleverelephant.ca>
|
|
Date: Wed Apr 15 11:28:15 2020 -0700
|
|
|
|
clean build of all DD functionality from JTS
|
|
|
|
commit e42e9bc0ea3fd35bddc892fbe51b3de5677d8e57
|
|
Author: Paul Ramsey <pramsey@cleverelephant.ca>
|
|
Date: Tue Apr 14 17:27:45 2020 -0700
|
|
|
|
DD wip
|
|
---
|
|
.codecov.yml | 1 -
|
|
Makefile.am | 1 -
|
|
configure.ac | 3 +-
|
|
doc/Doxyfile.in | 1 -
|
|
include/geos/Makefile.am | 1 +
|
|
include/geos/algorithm/CGAlgorithmsDD.h | 16 +-
|
|
include/geos/algorithm/Makefile.am | 3 +-
|
|
include/geos/algorithm/RayCrossingCounterDD.h | 1 -
|
|
include/geos/algorithm/ttmath/COPYRIGHT | 28 -
|
|
include/geos/algorithm/ttmath/Makefile.am | 24 -
|
|
include/geos/algorithm/ttmath/README | 23 -
|
|
include/geos/algorithm/ttmath/ttmath.h | 2880 --------
|
|
include/geos/algorithm/ttmath/ttmathbig.h | 6093 -----------------
|
|
include/geos/algorithm/ttmath/ttmathdec.h | 419 --
|
|
include/geos/algorithm/ttmath/ttmathint.h | 1923 ------
|
|
include/geos/algorithm/ttmath/ttmathmisc.h | 250 -
|
|
include/geos/algorithm/ttmath/ttmathobjects.h | 812 ---
|
|
include/geos/algorithm/ttmath/ttmathparser.h | 2777 --------
|
|
include/geos/algorithm/ttmath/ttmaththreads.h | 252 -
|
|
include/geos/algorithm/ttmath/ttmathtypes.h | 718 --
|
|
include/geos/algorithm/ttmath/ttmathuint.h | 4189 ------------
|
|
.../geos/algorithm/ttmath/ttmathuint_noasm.h | 1038 ---
|
|
.../geos/algorithm/ttmath/ttmathuint_x86.h | 1620 -----
|
|
.../geos/algorithm/ttmath/ttmathuint_x86_64.h | 1177 ----
|
|
.../ttmath/ttmathuint_x86_64_msvc.asm | 551 --
|
|
include/geos/math/DD.h | 204 +
|
|
include/geos/math/Makefile.am | 11 +
|
|
src/Makefile.am | 2 +
|
|
src/algorithm/CGAlgorithmsDD.cpp | 7 +-
|
|
src/algorithm/InteriorPointArea.cpp | 1 -
|
|
src/geom/LineString.cpp | 2 +-
|
|
src/math/DD.cpp | 403 ++
|
|
src/math/Makefile.am | 13 +
|
|
tests/unit/Makefile.am | 1 +
|
|
tests/unit/math/DDTest.cpp | 414 ++
|
|
35 files changed, 1059 insertions(+), 24800 deletions(-)
|
|
delete mode 100644 include/geos/algorithm/ttmath/COPYRIGHT
|
|
delete mode 100644 include/geos/algorithm/ttmath/Makefile.am
|
|
delete mode 100644 include/geos/algorithm/ttmath/README
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmath.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathbig.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathdec.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathint.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathmisc.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathobjects.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathparser.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmaththreads.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathtypes.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathuint.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathuint_noasm.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathuint_x86.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathuint_x86_64.h
|
|
delete mode 100644 include/geos/algorithm/ttmath/ttmathuint_x86_64_msvc.asm
|
|
create mode 100644 include/geos/math/DD.h
|
|
create mode 100644 include/geos/math/Makefile.am
|
|
create mode 100644 src/math/DD.cpp
|
|
create mode 100644 src/math/Makefile.am
|
|
create mode 100644 tests/unit/math/DDTest.cpp
|
|
|
|
diff --git a/Makefile.am b/Makefile.am
|
|
index dbc74514..f064d45d 100644
|
|
--- a/Makefile.am
|
|
+++ b/Makefile.am
|
|
@@ -73,5 +73,4 @@ valgrindcheck:
|
|
check-local:
|
|
! find $(srcdir) -name '*.cpp' -o -name '*.h' | \
|
|
grep -v tests/xmltester/tinyxml | \
|
|
- grep -v include/geos/algorithm/ttmath | \
|
|
xargs grep -n '[[:space:]]$$'
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 86778874..80d72e36 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -421,7 +421,6 @@ AC_OUTPUT([
|
|
include/geos/algorithm/Makefile
|
|
include/geos/algorithm/locate/Makefile
|
|
include/geos/algorithm/distance/Makefile
|
|
- include/geos/algorithm/ttmath/Makefile
|
|
include/geos/geom/Makefile
|
|
include/geos/geom/prep/Makefile
|
|
include/geos/geom/util/Makefile
|
|
@@ -436,6 +435,7 @@ AC_OUTPUT([
|
|
include/geos/index/sweepline/Makefile
|
|
include/geos/io/Makefile
|
|
include/geos/linearref/Makefile
|
|
+ include/geos/math/Makefile
|
|
include/geos/noding/Makefile
|
|
include/geos/noding/snapround/Makefile
|
|
include/geos/operation/Makefile
|
|
@@ -468,6 +468,7 @@ AC_OUTPUT([
|
|
src/index/sweepline/Makefile
|
|
src/io/Makefile
|
|
src/linearref/Makefile
|
|
+ src/math/Makefile
|
|
src/noding/Makefile
|
|
src/noding/snapround/Makefile
|
|
src/operation/Makefile
|
|
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
|
|
index c8415081..03d9e5f7 100644
|
|
--- a/doc/Doxyfile.in
|
|
+++ b/doc/Doxyfile.in
|
|
@@ -853,7 +853,6 @@ EXCLUDE_PATTERNS = */examples/* \
|
|
*/test/* \
|
|
*/bigtest/* \
|
|
*/io/markup/* \
|
|
- */ttmath/* \
|
|
config.h \
|
|
acconfig.h \
|
|
CoordinateList.cpp \
|
|
diff --git a/include/geos/Makefile.am b/include/geos/Makefile.am
|
|
index cc55c4ac..04e85f8f 100644
|
|
--- a/include/geos/Makefile.am
|
|
+++ b/include/geos/Makefile.am
|
|
@@ -8,6 +8,7 @@ SUBDIRS = \
|
|
index \
|
|
io \
|
|
linearref \
|
|
+ math \
|
|
noding \
|
|
operation \
|
|
planargraph \
|
|
diff --git a/include/geos/algorithm/CGAlgorithmsDD.h b/include/geos/algorithm/CGAlgorithmsDD.h
|
|
index f596466c..583532c1 100644
|
|
--- a/include/geos/algorithm/CGAlgorithmsDD.h
|
|
+++ b/include/geos/algorithm/CGAlgorithmsDD.h
|
|
@@ -19,17 +19,7 @@
|
|
#ifndef GEOS_ALGORITHM_CGALGORITHMDD_H
|
|
#define GEOS_ALGORITHM_CGALGORITHMDD_H
|
|
#include <geos/export.h>
|
|
-#include <geos/algorithm/ttmath/ttmath.h>
|
|
-
|
|
-/// \file CGAlgorithmsDD.h
|
|
-
|
|
-/// \brief Close to DoubleDouble equivalent used by JTS
|
|
-///
|
|
-/// Usage: `ttmath::Big<exponent, mantissa>`
|
|
-typedef ttmath::Big<TTMATH_BITS(32), TTMATH_BITS(128)> DD;
|
|
-//typedef ttmath::Big<TTMATH_BITS(64), TTMATH_BITS(128)> DD;
|
|
-//typedef ttmath::Big<TTMATH_BITS(32), TTMATH_BITS(256)> DD;
|
|
-//typedef ttmath::Big<TTMATH_BITS(64), TTMATH_BITS(256)> DD;
|
|
+#include <geos/math/DD.h>
|
|
|
|
// Forward declarations
|
|
namespace geos {
|
|
@@ -39,6 +29,8 @@ class CoordinateSequence;
|
|
}
|
|
}
|
|
|
|
+using namespace geos::math;
|
|
+
|
|
namespace geos {
|
|
namespace algorithm { // geos::algorithm
|
|
|
|
@@ -139,7 +131,7 @@ public:
|
|
* The circumcentre does not necessarily lie within the triangle. For example,
|
|
* the circumcentre of an obtuse isosceles triangle lies outside the triangle.
|
|
*
|
|
- * This method uses @ref DD extended-precision arithmetic to provide more accurate
|
|
+ * This method uses @ref geos::math::DD extended-precision arithmetic to provide more accurate
|
|
* results than [circumcentre(Coordinate, Coordinate, Coordinate)]
|
|
* (@ref geos::geom::Triangle::circumcentre(const Coordinate& p0, const Coordinate& p1, const Coordinate& p2)).
|
|
*
|
|
diff --git a/include/geos/algorithm/Makefile.am b/include/geos/algorithm/Makefile.am
|
|
index 717e63d8..dbd5a619 100644
|
|
--- a/include/geos/algorithm/Makefile.am
|
|
+++ b/include/geos/algorithm/Makefile.am
|
|
@@ -3,8 +3,7 @@
|
|
#
|
|
SUBDIRS = \
|
|
locate \
|
|
- distance \
|
|
- ttmath
|
|
+ distance
|
|
|
|
EXTRA_DIST =
|
|
|
|
diff --git a/include/geos/algorithm/RayCrossingCounterDD.h b/include/geos/algorithm/RayCrossingCounterDD.h
|
|
index 2328ab3e..d7ba41e3 100644
|
|
--- a/include/geos/algorithm/RayCrossingCounterDD.h
|
|
+++ b/include/geos/algorithm/RayCrossingCounterDD.h
|
|
@@ -22,7 +22,6 @@
|
|
|
|
#include <geos/export.h>
|
|
#include <geos/geom/Location.h>
|
|
-#include <geos/algorithm/ttmath/ttmath.h>
|
|
|
|
#include <vector>
|
|
|
|
diff --git a/include/geos/math/DD.h b/include/geos/math/DD.h
|
|
new file mode 100644
|
|
index 00000000..7bcbb183
|
|
--- /dev/null
|
|
+++ b/include/geos/math/DD.h
|
|
@@ -0,0 +1,204 @@
|
|
+/**********************************************************************
|
|
+ *
|
|
+ * GEOS - Geometry Engine Open Source
|
|
+ * http://geos.osgeo.org
|
|
+ *
|
|
+ * Copyright (C) 2020 Crunchy Data
|
|
+ *
|
|
+ * This is free software; you can redistribute and/or modify it under
|
|
+ * the terms of the GNU Lesser General Public Licence as published
|
|
+ * by the Free Software Foundation.
|
|
+ * See the COPYING file for more information.
|
|
+ *
|
|
+ **********************************************************************/
|
|
+
|
|
+/**
|
|
+ * Implements extended-precision floating-point numbers
|
|
+ * which maintain 106 bits (approximately 30 decimal digits) of precision.
|
|
+ * <p>
|
|
+ * A DoubleDouble uses a representation containing two double-precision values.
|
|
+ * A number x is represented as a pair of doubles, x.hi and x.lo,
|
|
+ * such that the number represented by x is x.hi + x.lo, where
|
|
+ * <pre>
|
|
+ * |x.lo| <= 0.5*ulp(x.hi)
|
|
+ * </pre>
|
|
+ * and ulp(y) means "unit in the last place of y".
|
|
+ * The basic arithmetic operations are implemented using
|
|
+ * convenient properties of IEEE-754 floating-point arithmetic.
|
|
+ * <p>
|
|
+ * The range of values which can be represented is the same as in IEEE-754.
|
|
+ * The precision of the representable numbers
|
|
+ * is twice as great as IEEE-754 double precision.
|
|
+ * <p>
|
|
+ * The correctness of the arithmetic algorithms relies on operations
|
|
+ * being performed with standard IEEE-754 double precision and rounding.
|
|
+ * This is the Java standard arithmetic model, but for performance reasons
|
|
+ * Java implementations are not
|
|
+ * constrained to using this standard by default.
|
|
+ * Some processors (notably the Intel Pentium architecture) perform
|
|
+ * floating point operations in (non-IEEE-754-standard) extended-precision.
|
|
+ * A JVM implementation may choose to use the non-standard extended-precision
|
|
+ * as its default arithmetic mode.
|
|
+ * To prevent this from happening, this code uses the
|
|
+ * Java <tt>strictfp</tt> modifier,
|
|
+ * which forces all operations to take place in the standard IEEE-754 rounding model.
|
|
+ * <p>
|
|
+ * The API provides both a set of value-oriented operations
|
|
+ * and a set of mutating operations.
|
|
+ * Value-oriented operations treat DoubleDouble values as
|
|
+ * immutable; operations on them return new objects carrying the result
|
|
+ * of the operation. This provides a simple and safe semantics for
|
|
+ * writing DoubleDouble expressions. However, there is a performance
|
|
+ * penalty for the object allocations required.
|
|
+ * The mutable interface updates object values in-place.
|
|
+ * It provides optimum memory performance, but requires
|
|
+ * care to ensure that aliasing errors are not created
|
|
+ * and constant values are not changed.
|
|
+ * <p>
|
|
+ * For example, the following code example constructs three DD instances:
|
|
+ * two to hold the input values and one to hold the result of the addition.
|
|
+ * <pre>
|
|
+ * DD a = new DD(2.0);
|
|
+ * DD b = new DD(3.0);
|
|
+ * DD c = a.add(b);
|
|
+ * </pre>
|
|
+ * In contrast, the following approach uses only one object:
|
|
+ * <pre>
|
|
+ * DD a = new DD(2.0);
|
|
+ * a.selfAdd(3.0);
|
|
+ * </pre>
|
|
+ * <p>
|
|
+ * This implementation uses algorithms originally designed variously by
|
|
+ * Knuth, Kahan, Dekker, and Linnainmaa.
|
|
+ * Douglas Priest developed the first C implementation of these techniques.
|
|
+ * Other more recent C++ implementation are due to Keith M. Briggs and David Bailey et al.
|
|
+ *
|
|
+ * <h3>References</h3>
|
|
+ * <ul>
|
|
+ * <li>Priest, D., <i>Algorithms for Arbitrary Precision Floating Point Arithmetic</i>,
|
|
+ * in P. Kornerup and D. Matula, Eds., Proc. 10th Symposium on Computer Arithmetic,
|
|
+ * IEEE Computer Society Press, Los Alamitos, Calif., 1991.
|
|
+ * <li>Yozo Hida, Xiaoye S. Li and David H. Bailey,
|
|
+ * <i>Quad-Double Arithmetic: Algorithms, Implementation, and Application</i>,
|
|
+ * manuscript, Oct 2000; Lawrence Berkeley National Laboratory Report BNL-46996.
|
|
+ * <li>David Bailey, <i>High Precision Software Directory</i>;
|
|
+ * <tt>http://crd.lbl.gov/~dhbailey/mpdist/index.html</tt>
|
|
+ * </ul>
|
|
+ *
|
|
+ *
|
|
+ * @author Martin Davis
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef GEOS_MATH_DD_H
|
|
+#define GEOS_MATH_DD_H
|
|
+
|
|
+#include <cmath>
|
|
+
|
|
+namespace geos {
|
|
+namespace math { // geos.math
|
|
+
|
|
+/**
|
|
+ * \class DD
|
|
+ *
|
|
+ * \brief
|
|
+ * Wrapper for DoubleDouble higher precision mathematics
|
|
+ * operations.
|
|
+ */
|
|
+class GEOS_DLL DD {
|
|
+ private:
|
|
+ static constexpr double SPLIT = 134217729.0; // 2^27+1, for IEEE double
|
|
+ double hi;
|
|
+ double lo;
|
|
+
|
|
+ int magnitude(double x) const;
|
|
+ int signum() const;
|
|
+ DD rint() const;
|
|
+
|
|
+
|
|
+ public:
|
|
+ DD(double p_hi, double p_lo) : hi(p_hi), lo(p_lo) {};
|
|
+ DD(double x) : hi(x), lo(0.0) {};
|
|
+ DD(const DD &dd) : hi(dd.hi), lo(dd.lo) {};
|
|
+ DD() : hi(0.0), lo(0.0) {};
|
|
+
|
|
+ bool operator==(const DD &rhs) const
|
|
+ {
|
|
+ return hi == rhs.hi && lo == rhs.lo;
|
|
+ }
|
|
+
|
|
+ bool operator!=(const DD &rhs) const
|
|
+ {
|
|
+ return hi != rhs.hi || lo != rhs.lo;
|
|
+ }
|
|
+
|
|
+ bool operator<(const DD &rhs) const
|
|
+ {
|
|
+ return (hi < rhs.hi) || (hi == rhs.hi && lo < rhs.lo);
|
|
+ }
|
|
+
|
|
+ bool operator<=(const DD &rhs) const
|
|
+ {
|
|
+ return (hi < rhs.hi) || (hi == rhs.hi && lo <= rhs.lo);
|
|
+ }
|
|
+
|
|
+ bool operator>(const DD &rhs) const
|
|
+ {
|
|
+ return (hi > rhs.hi) || (hi == rhs.hi && lo > rhs.lo);
|
|
+ }
|
|
+
|
|
+ bool operator>=(const DD &rhs) const
|
|
+ {
|
|
+ return (hi > rhs.hi) || (hi == rhs.hi && lo >= rhs.lo);
|
|
+ }
|
|
+
|
|
+ friend DD operator+ (const DD &lhs, const DD &rhs);
|
|
+ friend DD operator+ (const DD &lhs, double rhs);
|
|
+ friend DD operator- (const DD &lhs, const DD &rhs);
|
|
+ friend DD operator- (const DD &lhs, double rhs);
|
|
+ friend DD operator* (const DD &lhs, const DD &rhs);
|
|
+ friend DD operator* (const DD &lhs, double rhs);
|
|
+ friend DD operator/ (const DD &lhs, const DD &rhs);
|
|
+ friend DD operator/ (const DD &lhs, double rhs);
|
|
+
|
|
+ static DD determinant(const DD &x1, const DD &y1, const DD &x2, const DD &y2);
|
|
+ static DD determinant(double x1, double y1, double x2, double y2);
|
|
+ static DD abs(const DD &d);
|
|
+ static DD pow(const DD &d, int exp);
|
|
+ static DD trunc(const DD &d);
|
|
+
|
|
+ bool isNaN() const;
|
|
+ bool isNegative() const;
|
|
+ bool isPositive() const;
|
|
+ bool isZero() const;
|
|
+ double doubleValue() const;
|
|
+ double ToDouble() const { return doubleValue(); }
|
|
+ int intValue() const;
|
|
+ DD negate() const;
|
|
+ DD reciprocal() const;
|
|
+ DD floor() const;
|
|
+ DD ceil() const;
|
|
+
|
|
+ void selfAdd(const DD &d);
|
|
+ void selfAdd(double p_hi, double p_lo);
|
|
+ void selfAdd(double y);
|
|
+
|
|
+ void selfSubtract(const DD &d);
|
|
+ void selfSubtract(double p_hi, double p_lo);
|
|
+ void selfSubtract(double y);
|
|
+
|
|
+ void selfMultiply(double p_hi, double p_lo);
|
|
+ void selfMultiply(const DD &d);
|
|
+ void selfMultiply(double y);
|
|
+
|
|
+ void selfDivide(double p_hi, double p_lo);
|
|
+ void selfDivide(const DD &d);
|
|
+ void selfDivide(double y);
|
|
+};
|
|
+
|
|
+
|
|
+} // namespace geos::math
|
|
+} // namespace geos
|
|
+
|
|
+
|
|
+#endif // GEOS_MATH_DD_H
|
|
diff --git a/include/geos/math/Makefile.am b/include/geos/math/Makefile.am
|
|
new file mode 100644
|
|
index 00000000..5396b951
|
|
--- /dev/null
|
|
+++ b/include/geos/math/Makefile.am
|
|
@@ -0,0 +1,11 @@
|
|
+#
|
|
+# This file is part of project GEOS (http://trac.osgeo.org/geos/)
|
|
+#
|
|
+SUBDIRS =
|
|
+
|
|
+EXTRA_DIST =
|
|
+
|
|
+geosdir = $(includedir)/geos/math
|
|
+
|
|
+geos_HEADERS = \
|
|
+ DD.h
|
|
diff --git a/src/Makefile.am b/src/Makefile.am
|
|
index 1bba8e87..ea465248 100644
|
|
--- a/src/Makefile.am
|
|
+++ b/src/Makefile.am
|
|
@@ -7,6 +7,7 @@ SUBDIRS = \
|
|
index \
|
|
io \
|
|
linearref \
|
|
+ math \
|
|
noding \
|
|
operation \
|
|
planargraph \
|
|
@@ -39,6 +40,7 @@ libgeos_la_LIBADD = \
|
|
index/libindex.la \
|
|
io/libio.la \
|
|
linearref/liblinearref.la \
|
|
+ math/libmath.la \
|
|
noding/libnoding.la \
|
|
operation/liboperation.la \
|
|
planargraph/libplanargraph.la \
|
|
diff --git a/src/algorithm/CGAlgorithmsDD.cpp b/src/algorithm/CGAlgorithmsDD.cpp
|
|
index c25c1f28..c484c1f6 100644
|
|
--- a/src/algorithm/CGAlgorithmsDD.cpp
|
|
+++ b/src/algorithm/CGAlgorithmsDD.cpp
|
|
@@ -35,7 +35,7 @@ namespace {
|
|
double constexpr DP_SAFE_EPSILON = 1e-15;
|
|
|
|
inline int
|
|
-OrientationDD(DD const& dd)
|
|
+OrientationDD(const DD &dd)
|
|
{
|
|
static DD const zero(0.0);
|
|
if(dd < zero) {
|
|
@@ -49,10 +49,7 @@ OrientationDD(DD const& dd)
|
|
return CGAlgorithmsDD::STRAIGHT;
|
|
}
|
|
|
|
-// inline std::string ToStringDD(DD const& dd)
|
|
-// {
|
|
-// return dd.ToString();
|
|
-// }
|
|
+
|
|
}
|
|
|
|
namespace geos {
|
|
diff --git a/src/algorithm/InteriorPointArea.cpp b/src/algorithm/InteriorPointArea.cpp
|
|
index 1ddddac9..61c36fd0 100644
|
|
--- a/src/algorithm/InteriorPointArea.cpp
|
|
+++ b/src/algorithm/InteriorPointArea.cpp
|
|
@@ -200,7 +200,6 @@ private:
|
|
// edge intersects scan line, so add a crossing
|
|
double xInt = intersection(p0, p1, scanY);
|
|
crossings.push_back(xInt);
|
|
- //checkIntersectionDD(p0, p1, scanY, xInt);
|
|
}
|
|
|
|
void findBestMidpoint(vector<double>& crossings)
|
|
diff --git a/src/geom/LineString.cpp b/src/geom/LineString.cpp
|
|
index 65f86a0d..ac5d7fe6 100644
|
|
--- a/src/geom/LineString.cpp
|
|
+++ b/src/geom/LineString.cpp
|
|
@@ -45,7 +45,7 @@ using namespace geos::algorithm;
|
|
namespace geos {
|
|
namespace geom { // geos::geom
|
|
|
|
-LineString::~LineString(){};
|
|
+LineString::~LineString(){}
|
|
|
|
/*protected*/
|
|
LineString::LineString(const LineString& ls)
|
|
diff --git a/src/math/DD.cpp b/src/math/DD.cpp
|
|
new file mode 100644
|
|
index 00000000..673e9217
|
|
--- /dev/null
|
|
+++ b/src/math/DD.cpp
|
|
@@ -0,0 +1,403 @@
|
|
+/**********************************************************************
|
|
+ *
|
|
+ * GEOS - Geometry Engine Open Source
|
|
+ * http://geos.osgeo.org
|
|
+ *
|
|
+ * Copyright (C) 2020 Crunchy Data
|
|
+ *
|
|
+ * This is free software; you can redistribute and/or modify it under
|
|
+ * the terms of the GNU Lesser General Public Licence as published
|
|
+ * by the Free Software Foundation.
|
|
+ * See the COPYING file for more information.
|
|
+ *
|
|
+ **********************************************************************/
|
|
+
|
|
+#include <cmath>
|
|
+
|
|
+#include <geos/profiler.h>
|
|
+#include <geos/math/DD.h>
|
|
+
|
|
+namespace geos {
|
|
+namespace math { // geos.util
|
|
+
|
|
+
|
|
+/* private */
|
|
+int
|
|
+DD::magnitude(double x) const
|
|
+{
|
|
+ double xAbs = std::fabs(x);
|
|
+ double xLog10 = std::log(xAbs) / std::log(10);
|
|
+ int xMag = (int) std::floor(xLog10);
|
|
+ /**
|
|
+ * Since log computation is inexact, there may be an off-by-one error
|
|
+ * in the computed magnitude.
|
|
+ * Following tests that magnitude is correct, and adjusts it if not
|
|
+ */
|
|
+ double xApprox = std::pow(10, xMag);
|
|
+ if (xApprox * 10 <= xAbs)
|
|
+ xMag += 1;
|
|
+
|
|
+ return xMag;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+bool DD::isNaN() const
|
|
+{
|
|
+ return std::isnan(hi);
|
|
+}
|
|
+/* public */
|
|
+bool DD::isNegative() const
|
|
+{
|
|
+ return hi < 0.0 || (hi == 0.0 && lo < 0.0);
|
|
+}
|
|
+/* public */
|
|
+bool DD::isPositive() const
|
|
+{
|
|
+ return hi > 0.0 || (hi == 0.0 && lo > 0.0);
|
|
+}
|
|
+/* public */
|
|
+bool DD::isZero() const
|
|
+{
|
|
+ return hi == 0.0 && lo == 0.0;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+double DD::doubleValue() const
|
|
+{
|
|
+ return hi + lo;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+int DD::intValue() const
|
|
+{
|
|
+ return (int) hi;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+void DD::selfAdd(const DD &y)
|
|
+{
|
|
+ return selfAdd(y.hi, y.lo);
|
|
+}
|
|
+
|
|
+/* public */
|
|
+void DD::selfAdd(double yhi, double ylo)
|
|
+{
|
|
+ double H, h, T, t, S, s, e, f;
|
|
+ S = hi + yhi;
|
|
+ T = lo + ylo;
|
|
+ e = S - hi;
|
|
+ f = T - lo;
|
|
+ s = S-e;
|
|
+ t = T-f;
|
|
+ s = (yhi-e)+(hi-s);
|
|
+ t = (ylo-f)+(lo-t);
|
|
+ e = s+T; H = S+e; h = e+(S-H); e = t+h;
|
|
+
|
|
+ double zhi = H + e;
|
|
+ double zlo = e + (H - zhi);
|
|
+ hi = zhi;
|
|
+ lo = zlo;
|
|
+ return;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+void DD::selfAdd(double y)
|
|
+{
|
|
+ double H, h, S, s, e, f;
|
|
+ S = hi + y;
|
|
+ e = S - hi;
|
|
+ s = S - e;
|
|
+ s = (y - e) + (hi - s);
|
|
+ f = s + lo;
|
|
+ H = S + f;
|
|
+ h = f + (S - H);
|
|
+ hi = H + h;
|
|
+ lo = h + (H - hi);
|
|
+ return;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+DD operator+(const DD &lhs, const DD &rhs)
|
|
+{
|
|
+ DD rv(lhs.hi, lhs.lo);
|
|
+ rv.selfAdd(rhs);
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+DD operator+(const DD &lhs, double rhs)
|
|
+{
|
|
+ DD rv(lhs.hi, lhs.lo);
|
|
+ rv.selfAdd(rhs);
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+void DD::selfSubtract(const DD &d)
|
|
+{
|
|
+ return selfAdd(-1*d.hi, -1*d.lo);
|
|
+}
|
|
+
|
|
+/* public */
|
|
+void DD::selfSubtract(double p_hi, double p_lo)
|
|
+{
|
|
+ return selfAdd(-1*p_hi, -1*p_lo);
|
|
+}
|
|
+
|
|
+/* public */
|
|
+void DD::selfSubtract(double y)
|
|
+{
|
|
+ return selfAdd(-1*y, 0.0);
|
|
+}
|
|
+
|
|
+/* public */
|
|
+DD operator-(const DD &lhs, const DD &rhs)
|
|
+{
|
|
+ DD rv(lhs.hi, lhs.lo);
|
|
+ rv.selfSubtract(rhs);
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+DD operator-(const DD &lhs, double rhs)
|
|
+{
|
|
+ DD rv(lhs.hi, lhs.lo);
|
|
+ rv.selfSubtract(rhs);
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+void DD::selfMultiply(double yhi, double ylo)
|
|
+{
|
|
+ double hx, tx, hy, ty, C, c;
|
|
+ C = SPLIT * hi; hx = C-hi; c = SPLIT * yhi;
|
|
+ hx = C-hx; tx = hi-hx; hy = c-yhi;
|
|
+ C = hi*yhi; hy = c-hy; ty = yhi-hy;
|
|
+ c = ((((hx*hy-C)+hx*ty)+tx*hy)+tx*ty)+(hi*ylo+lo*yhi);
|
|
+ double zhi = C+c; hx = C-zhi;
|
|
+ double zlo = c+hx;
|
|
+ hi = zhi;
|
|
+ lo = zlo;
|
|
+ return;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+void DD::selfMultiply(DD const &d)
|
|
+{
|
|
+ return selfMultiply(d.hi, d.lo);
|
|
+}
|
|
+
|
|
+/* public */
|
|
+void DD::selfMultiply(double y)
|
|
+{
|
|
+ return selfMultiply(y, 0.0);
|
|
+}
|
|
+
|
|
+/* public */
|
|
+DD operator*(const DD &lhs, const DD &rhs)
|
|
+{
|
|
+ DD rv(lhs.hi, lhs.lo);
|
|
+ rv.selfMultiply(rhs);
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+DD operator*(const DD &lhs, double rhs)
|
|
+{
|
|
+ DD rv(lhs.hi, lhs.lo);
|
|
+ rv.selfMultiply(rhs);
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+
|
|
+/* public */
|
|
+void DD::selfDivide(double yhi, double ylo)
|
|
+{
|
|
+ double hc, tc, hy, ty, C, c, U, u;
|
|
+ C = hi/yhi; c = SPLIT*C; hc =c-C;
|
|
+ u = SPLIT*yhi; hc = c-hc;
|
|
+ tc = C-hc; hy = u-yhi; U = C * yhi;
|
|
+ hy = u-hy; ty = yhi-hy;
|
|
+ u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty;
|
|
+ c = ((((hi-U)-u)+lo)-C*ylo)/yhi;
|
|
+ u = C+c;
|
|
+ hi = u;
|
|
+ lo = (C-u)+c;
|
|
+ return;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+void DD::selfDivide(const DD &d)
|
|
+{
|
|
+ return selfDivide(d.hi, d.lo);
|
|
+}
|
|
+
|
|
+/* public */
|
|
+void DD::selfDivide(double y)
|
|
+{
|
|
+ return selfDivide(y, 0.0);
|
|
+}
|
|
+
|
|
+/* public */
|
|
+DD operator/(const DD &lhs, const DD &rhs)
|
|
+{
|
|
+ DD rv(lhs.hi, lhs.lo);
|
|
+ rv.selfDivide(rhs);
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+DD operator/(const DD &lhs, double rhs)
|
|
+{
|
|
+ DD rv(lhs.hi, lhs.lo);
|
|
+ rv.selfDivide(rhs);
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+/* public */
|
|
+DD DD::negate() const
|
|
+{
|
|
+ DD rv(hi, lo);
|
|
+ if (rv.isNaN())
|
|
+ {
|
|
+ return rv;
|
|
+ }
|
|
+ rv.hi = -hi;
|
|
+ rv.lo = -lo;
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+/* public static */
|
|
+DD DD::reciprocal() const
|
|
+{
|
|
+ double hc, tc, hy, ty, C, c, U, u;
|
|
+ C = 1.0/hi;
|
|
+ c = SPLIT*C;
|
|
+ hc = c-C;
|
|
+ u = SPLIT*hi;
|
|
+ hc = c-hc; tc = C-hc; hy = u-hi; U = C*hi; hy = u-hy; ty = hi-hy;
|
|
+ u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty;
|
|
+ c = ((((1.0-U)-u))-C*lo)/hi;
|
|
+ double zhi = C+c;
|
|
+ double zlo = (C-zhi)+c;
|
|
+ return DD(zhi, zlo);
|
|
+}
|
|
+
|
|
+DD DD::floor() const
|
|
+{
|
|
+ DD rv(hi, lo);
|
|
+ if (isNaN()) return rv;
|
|
+ double fhi = std::floor(hi);
|
|
+ double flo = 0.0;
|
|
+ // Hi is already integral. Floor the low word
|
|
+ if (fhi == hi) {
|
|
+ flo = std::floor(lo);
|
|
+ }
|
|
+ // do we need to renormalize here?
|
|
+ rv.hi = fhi;
|
|
+ rv.lo = flo;
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+DD DD::ceil() const
|
|
+{
|
|
+ DD rv(hi, lo);
|
|
+ if (isNaN()) return rv;
|
|
+ double fhi = std::ceil(hi);
|
|
+ double flo = 0.0;
|
|
+ // Hi is already integral. Ceil the low word
|
|
+ if (fhi == hi) {
|
|
+ flo = std::ceil(lo);
|
|
+ // do we need to renormalize here?
|
|
+ }
|
|
+ rv.hi = fhi;
|
|
+ rv.lo = flo;
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+int DD::signum() const
|
|
+{
|
|
+ if (hi > 0) return 1;
|
|
+ if (hi < 0) return -1;
|
|
+ if (lo > 0) return 1;
|
|
+ if (lo < 0) return -1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+DD DD::rint() const
|
|
+{
|
|
+ DD rv(hi, lo);
|
|
+ if (isNaN()) return rv;
|
|
+ return (rv + 0.5).floor();
|
|
+}
|
|
+
|
|
+/* public static */
|
|
+DD DD::trunc(const DD &d)
|
|
+{
|
|
+ DD rv(d);
|
|
+ if (rv.isNaN()) return rv;
|
|
+ if (rv.isPositive())
|
|
+ return rv.floor();
|
|
+ return rv.ceil();
|
|
+}
|
|
+
|
|
+/* public static */
|
|
+DD DD::abs(const DD &d)
|
|
+{
|
|
+ DD rv(d);
|
|
+ if (rv.isNaN()) return rv;
|
|
+ if (rv.isNegative())
|
|
+ return rv.negate();
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+/* public static */
|
|
+DD DD::determinant(const DD &x1, const DD &y1, const DD &x2, const DD &y2)
|
|
+{
|
|
+ return (x1 * y2) - (y1 * x2);
|
|
+}
|
|
+
|
|
+/* public static */
|
|
+DD DD::determinant(double x1, double y1, double x2, double y2)
|
|
+{
|
|
+ return determinant(DD(x1), DD(y1), DD(x2), DD(y2) );
|
|
+}
|
|
+
|
|
+/**
|
|
+* Computes the value of this number raised to an integral power.
|
|
+* Follows semantics of Java Math.pow as closely as possible.
|
|
+*/
|
|
+/* public static */
|
|
+DD DD::pow(const DD &d, int exp)
|
|
+{
|
|
+ if (exp == 0.0)
|
|
+ return DD(1.0);
|
|
+
|
|
+ DD r(d);
|
|
+ DD s(1.0);
|
|
+ int n = std::abs(exp);
|
|
+
|
|
+ if (n > 1) {
|
|
+ /* Use binary exponentiation */
|
|
+ while (n > 0) {
|
|
+ if (n % 2 == 1) {
|
|
+ s.selfMultiply(r);
|
|
+ }
|
|
+ n /= 2;
|
|
+ if (n > 0)
|
|
+ r = r*r;
|
|
+ }
|
|
+ } else {
|
|
+ s = r;
|
|
+ }
|
|
+
|
|
+ /* Compute the reciprocal if n is negative. */
|
|
+ if (exp < 0)
|
|
+ return s.reciprocal();
|
|
+ return s;
|
|
+}
|
|
+
|
|
+
|
|
+}
|
|
+}
|
|
diff --git a/src/math/Makefile.am b/src/math/Makefile.am
|
|
new file mode 100644
|
|
index 00000000..c30e97ea
|
|
--- /dev/null
|
|
+++ b/src/math/Makefile.am
|
|
@@ -0,0 +1,13 @@
|
|
+#
|
|
+# This file is part of project GEOS (http://trac.osgeo.org/geos/)
|
|
+#
|
|
+SUBDIRS =
|
|
+
|
|
+noinst_LTLIBRARIES = libmath.la
|
|
+
|
|
+AM_CPPFLAGS = -I$(top_srcdir)/include
|
|
+
|
|
+libmath_la_SOURCES = \
|
|
+ DD.cpp
|
|
+
|
|
+libmath_la_LIBADD =
|
|
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
|
|
index 88c4816f..3c836fc8 100644
|
|
--- a/tests/unit/Makefile.am
|
|
+++ b/tests/unit/Makefile.am
|
|
@@ -151,6 +151,7 @@ geos_unit_SOURCES = \
|
|
io/WKTWriterTest.cpp \
|
|
io/WriterTest.cpp \
|
|
linearref/LengthIndexedLineTest.cpp \
|
|
+ math/DDTest.cpp \
|
|
noding/BasicSegmentStringTest.cpp \
|
|
noding/NodedSegmentStringTest.cpp \
|
|
noding/OrientedCoordinateArrayTest.cpp \
|
|
diff --git a/tests/unit/math/DDTest.cpp b/tests/unit/math/DDTest.cpp
|
|
new file mode 100644
|
|
index 00000000..00a29b8f
|
|
--- /dev/null
|
|
+++ b/tests/unit/math/DDTest.cpp
|
|
@@ -0,0 +1,414 @@
|
|
+//
|
|
+// Test Suite for geos::util::UniqueCoordinateArrayFilter class.
|
|
+
|
|
+// geos
|
|
+
|
|
+#include <geos/profiler.h>
|
|
+#include <geos/math/DD.h>
|
|
+
|
|
+// tut
|
|
+#include <tut/tut.hpp>
|
|
+#include <utility.h>
|
|
+
|
|
+// std
|
|
+#include <memory>
|
|
+#include <string>
|
|
+
|
|
+using namespace geos::math;
|
|
+
|
|
+namespace tut {
|
|
+//
|
|
+// Test Group
|
|
+//
|
|
+
|
|
+// Common data used in test cases.
|
|
+struct test_dd_data {
|
|
+
|
|
+ double eps;
|
|
+ DD pi;
|
|
+ DD e;
|
|
+
|
|
+
|
|
+ void ensure_dd_equals(const char *str, const DD &d1, const DD &d2, double tolerance)
|
|
+ {
|
|
+ DD delta = DD::abs(d1 - d2);
|
|
+ double diff = delta.doubleValue();
|
|
+ ensure(str, diff <= tolerance);
|
|
+ }
|
|
+
|
|
+ void checkTrunc(const DD &x, const DD &expected)
|
|
+ {
|
|
+ DD trunc = DD::trunc(x);
|
|
+ ensure("checkTrunc", trunc == expected);
|
|
+ }
|
|
+
|
|
+ void checkDeterminant(double x1, double y1, double x2, double y2, double expected, double errBound)
|
|
+ {
|
|
+ DD det = DD::determinant(x1, y1, x2, y2);
|
|
+ //ensure_equals("1", Angle::angle(Coordinate(10, 0)), 0.0, TOL);
|
|
+ ensure_dd_equals("checkDeterminant", det, DD(expected), errBound);
|
|
+ }
|
|
+
|
|
+ void checkDeterminantDD(double x1, double y1, double x2, double y2, double expected, double errBound)
|
|
+ {
|
|
+ DD det = DD::determinant(DD(x1), DD(y1), DD(x2), DD(y2));
|
|
+ ensure_dd_equals("checkDeterminantDD", det, DD(expected), errBound);
|
|
+ }
|
|
+
|
|
+ void checkAddMult2(const DD &dd)
|
|
+ {
|
|
+ DD sum = dd + dd;
|
|
+ DD prod = dd * DD(2.0);
|
|
+ ensure_dd_equals("checkAddMult2", sum, prod, 0.0);
|
|
+ }
|
|
+
|
|
+ void checkMultiplyDivide(const DD &a, const DD &b, double errBound)
|
|
+ {
|
|
+ DD a2 = (a * b) / b;
|
|
+ ensure_dd_equals("checkMultiplyDivide", a, a2, errBound);
|
|
+ }
|
|
+
|
|
+ void checkDivideMultiply(const DD &a, const DD &b, double errBound)
|
|
+ {
|
|
+ DD a2 = (a / b) * b;
|
|
+ ensure_dd_equals("checkDivideMultiply", a, a2, errBound);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Computes (a+b)^2 in two different ways and compares the result.
|
|
+ * For correct results, a and b should be integers.
|
|
+ */
|
|
+ void checkBinomialSquare(double a, double b)
|
|
+ {
|
|
+ // binomial square
|
|
+ DD add(a);
|
|
+ DD bdd(b);
|
|
+ DD aPlusb = add + bdd;
|
|
+ DD abSq = aPlusb * aPlusb;
|
|
+
|
|
+ // expansion
|
|
+ DD a2dd = add * add;
|
|
+ DD b2dd = bdd * bdd;
|
|
+ DD ab = add * bdd;
|
|
+ DD sum = b2dd + ab + ab;
|
|
+ DD diff = abSq - a2dd;
|
|
+ DD delta = diff - sum;
|
|
+
|
|
+ ensure("isSame", diff == sum);
|
|
+ ensure("isDeltaZero", delta.isZero());
|
|
+ }
|
|
+
|
|
+ void checkBinomial2(double a, double b)
|
|
+ {
|
|
+ // binomial product
|
|
+ DD add(a);
|
|
+ DD bdd(b);
|
|
+ DD aPlusb = add + bdd;
|
|
+ DD aSubb = add - bdd;
|
|
+ DD abProd = aPlusb * aSubb;
|
|
+
|
|
+ // expansion
|
|
+ DD a2dd = add * add;
|
|
+ DD b2dd = bdd * bdd;
|
|
+
|
|
+ // this should equal b^2
|
|
+ DD diff = (abProd - a2dd).negate();
|
|
+ DD delta = diff - b2dd;
|
|
+
|
|
+ ensure("isSame", diff == b2dd);
|
|
+ ensure("isDeltaZero", delta.isZero());
|
|
+ }
|
|
+
|
|
+ void checkReciprocal(double x, double errBound)
|
|
+ {
|
|
+ DD xdd(x);
|
|
+ DD rr = xdd.reciprocal().reciprocal();
|
|
+ double err = (xdd - rr).doubleValue();
|
|
+ ensure("checkReciprocal", err <= errBound);
|
|
+ }
|
|
+
|
|
+ DD slowPow(const DD &x, int exp)
|
|
+ {
|
|
+ if (exp == 0)
|
|
+ return DD(1.0);
|
|
+
|
|
+ int n = std::abs(exp);
|
|
+ // MD - could use binary exponentiation for better precision & speed
|
|
+ DD pow(x);
|
|
+ for (int i = 1; i < n; i++) {
|
|
+ pow = pow * x;
|
|
+ }
|
|
+ if (exp < 0) {
|
|
+ return pow.reciprocal();
|
|
+ }
|
|
+ return pow;
|
|
+ }
|
|
+
|
|
+ void checkPow(double x, int exp, double errBound)
|
|
+ {
|
|
+ DD xdd(x);
|
|
+ DD pow = DD::pow(xdd, exp);
|
|
+ DD pow2 = slowPow(xdd, exp);
|
|
+ double err = (pow - pow2).doubleValue();
|
|
+ ensure("checkPow", err <= errBound);
|
|
+ }
|
|
+
|
|
+
|
|
+ DD arctan(DD x)
|
|
+ {
|
|
+ DD t = x;
|
|
+ DD t2 = t*t;
|
|
+ DD at(0.0);
|
|
+ DD two(2.0);
|
|
+ int k = 0;
|
|
+ DD d(1.0);
|
|
+ int sign = 1;
|
|
+ while (t.doubleValue() > eps) {
|
|
+ k++;
|
|
+ if (sign < 0)
|
|
+ at = at - (t / d);
|
|
+ else
|
|
+ at = at + (t / d);
|
|
+
|
|
+ d = d + two;
|
|
+ t = t * t2;
|
|
+ sign = -sign;
|
|
+ }
|
|
+ return at;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Uses Taylor series to compute e
|
|
+ *
|
|
+ * e = 1 + 1 + 1/2! + 1/3! + 1/4! + ...
|
|
+ */
|
|
+ DD computeEByTaylorSeries()
|
|
+ {
|
|
+ DD s(2.0);
|
|
+ DD t(1.0);
|
|
+ double n = 1.0;
|
|
+ int i = 0;
|
|
+ while(t.doubleValue() > eps)
|
|
+ {
|
|
+ i++;
|
|
+ n += 1.0;
|
|
+ t = t / DD(n);
|
|
+ s = s + t;
|
|
+ }
|
|
+ return s;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Uses Machin's arctangent formula to compute Pi:
|
|
+ *
|
|
+ * Pi / 4 = 4 arctan(1/5) - arctan(1/239)
|
|
+ */
|
|
+
|
|
+ DD computePiByMachin()
|
|
+ {
|
|
+ DD t1 = DD(1.0) / DD(5.0);
|
|
+ DD t2 = DD(1.0) / DD(239.0);
|
|
+ DD pi4 = (DD(4.0) * arctan(t1)) - arctan(t2);
|
|
+ DD pi = DD(4.0) * pi4;
|
|
+ return pi;
|
|
+ }
|
|
+
|
|
+ test_dd_data():
|
|
+ eps(1.23259516440783e-32), /* = 2^-106 */
|
|
+ pi(DD(3.141592653589793116e+00, 1.224646799147353207e-16)),
|
|
+ e(DD(2.718281828459045091e+00, 1.445646891729250158e-16))
|
|
+ {}
|
|
+
|
|
+};
|
|
+
|
|
+typedef test_group<test_dd_data> group;
|
|
+typedef group::object object;
|
|
+
|
|
+group test_dd_group("geos::math::DD");
|
|
+
|
|
+//
|
|
+// Test Cases
|
|
+//
|
|
+
|
|
+// Test PI calculation
|
|
+template<>
|
|
+template<>
|
|
+void object::test<1>
|
|
+()
|
|
+{
|
|
+ DD testPi = computePiByMachin();
|
|
+ double err = std::abs((testPi - pi).doubleValue());
|
|
+ // std::cout << "Difference from PI = " << err << std::endl;
|
|
+ ensure("Test PI calculation", err < 8*eps);
|
|
+}
|
|
+
|
|
+// Test E calculation
|
|
+template<>
|
|
+template<>
|
|
+void object::test<2>
|
|
+()
|
|
+{
|
|
+ DD testE = computeEByTaylorSeries();
|
|
+ double err = std::abs((testE - e).doubleValue());
|
|
+ // std::cout << "Difference from E = " << err << std::endl;
|
|
+ ensure("Test E calculation", err < eps);
|
|
+}
|
|
+
|
|
+
|
|
+// Test NaN
|
|
+template<>
|
|
+template<>
|
|
+void object::test<3>
|
|
+()
|
|
+{
|
|
+ DD nan = DD(1.0) / DD(0.0);
|
|
+ ensure("isNan", nan.isNaN());
|
|
+ ensure("isNan", (DD(1.0) * nan).isNaN());
|
|
+}
|
|
+
|
|
+// testAddMult2
|
|
+template<>
|
|
+template<>
|
|
+void object::test<4>
|
|
+()
|
|
+{
|
|
+ checkAddMult2(DD(3.0));
|
|
+ checkAddMult2(DD(pi));
|
|
+}
|
|
+
|
|
+
|
|
+// testMultiplyDivide
|
|
+template<>
|
|
+template<>
|
|
+void object::test<5>
|
|
+()
|
|
+{
|
|
+ checkMultiplyDivide(DD(pi), DD(e), 1e-30);
|
|
+ checkMultiplyDivide(DD(DD(2.0)*pi), DD(e), 1e-30);
|
|
+ checkMultiplyDivide(DD(DD(0.5)*pi), DD(e), 1e-30);
|
|
+ checkMultiplyDivide(DD(39.4), DD(10), 1e-30);
|
|
+}
|
|
+
|
|
+
|
|
+// testDivideMultiply
|
|
+template<>
|
|
+template<>
|
|
+void object::test<6>
|
|
+()
|
|
+{
|
|
+ checkDivideMultiply(DD(pi), DD(e), 1e-30);
|
|
+ checkDivideMultiply(DD(39.4), DD(10), 1e-30);
|
|
+}
|
|
+
|
|
+
|
|
+// testTrunc
|
|
+template<>
|
|
+template<>
|
|
+void object::test<7>
|
|
+()
|
|
+{
|
|
+ checkTrunc(DD(1e16) - DD(1), DD(1e16) - DD(1));
|
|
+ // the appropriate error bound is determined empirically
|
|
+ checkTrunc(DD(pi), DD(3));
|
|
+ checkTrunc(DD(999.999), DD(999));
|
|
+
|
|
+ checkTrunc(DD(e).negate(), DD(-2));
|
|
+ checkTrunc(DD(-999.999), DD(-999));
|
|
+}
|
|
+
|
|
+// testPow
|
|
+template<>
|
|
+template<>
|
|
+void object::test<8>
|
|
+()
|
|
+{
|
|
+ checkPow(0, 3, 16 * eps);
|
|
+ checkPow(0, 3, 16 * eps);
|
|
+ checkPow(14, 3, 16 * eps);
|
|
+ checkPow(3, -5, 16 * eps);
|
|
+ checkPow(-3, 5, 16 * eps);
|
|
+ checkPow(-3, -5, 16 * eps);
|
|
+ checkPow(0.12345, -5, 1e5 * eps);
|
|
+}
|
|
+
|
|
+
|
|
+// testReciprocal
|
|
+template<>
|
|
+template<>
|
|
+void object::test<9>
|
|
+()
|
|
+{
|
|
+ checkReciprocal(3.0, 0);
|
|
+ checkReciprocal(99.0, 1e-29);
|
|
+ checkReciprocal(999.0, 0);
|
|
+ checkReciprocal(314159269.0, 0);
|
|
+}
|
|
+
|
|
+// testDeterminant
|
|
+template<>
|
|
+template<>
|
|
+void object::test<10>
|
|
+()
|
|
+{
|
|
+ checkDeterminant(3, 8, 4, 6, -14, 0);
|
|
+ checkDeterminantDD(3, 8, 4, 6, -14, 0);
|
|
+}
|
|
+
|
|
+// testDeterminantRobust
|
|
+template<>
|
|
+template<>
|
|
+void object::test<11>
|
|
+()
|
|
+{
|
|
+ checkDeterminant(1.0e9, 1.0e9 - 1, 1.0e9 - 1, 1.0e9 - 2, -1, 0);
|
|
+ checkDeterminantDD(1.0e9, 1.0e9 - 1, 1.0e9 - 1, 1.0e9 - 2, -1, 0);
|
|
+}
|
|
+
|
|
+
|
|
+// testBinom
|
|
+template<>
|
|
+template<>
|
|
+void object::test<12>
|
|
+()
|
|
+{
|
|
+ checkBinomialSquare(100.0, 1.0);
|
|
+ checkBinomialSquare(1000.0, 1.0);
|
|
+ checkBinomialSquare(10000.0, 1.0);
|
|
+ checkBinomialSquare(100000.0, 1.0);
|
|
+ checkBinomialSquare(1000000.0, 1.0);
|
|
+ checkBinomialSquare(1e8, 1.0);
|
|
+ checkBinomialSquare(1e10, 1.0);
|
|
+ checkBinomialSquare(1e14, 1.0);
|
|
+ // Following call will fail, because it requires 32 digits of precision
|
|
+ // checkBinomialSquare(1e16, 1.0);
|
|
+
|
|
+ checkBinomialSquare(1e14, 291.0);
|
|
+ checkBinomialSquare(5e14, 291.0);
|
|
+ checkBinomialSquare(5e14, 345291.0);
|
|
+}
|
|
+
|
|
+// testBinom2
|
|
+template<>
|
|
+template<>
|
|
+void object::test<13>
|
|
+()
|
|
+{
|
|
+ checkBinomial2(100.0, 1.0);
|
|
+ checkBinomial2(1000.0, 1.0);
|
|
+ checkBinomial2(10000.0, 1.0);
|
|
+ checkBinomial2(100000.0, 1.0);
|
|
+ checkBinomial2(1000000.0, 1.0);
|
|
+ checkBinomial2(1e8, 1.0);
|
|
+ checkBinomial2(1e10, 1.0);
|
|
+ checkBinomial2(1e14, 1.0);
|
|
+
|
|
+ checkBinomial2(1e14, 291.0);
|
|
+
|
|
+ checkBinomial2(5e14, 291.0);
|
|
+ checkBinomial2(5e14, 345291.0);
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+} // namespace tut
|
|
+
|
|
--
|
|
2.26.2
|
|
|