Skip to content

Commit 4e2135d

Browse files
committed
Created new constexpr DBL variable MIN_ISECT_DEPTH_RETURNED.
Near term need to use a value not MIN_ISECT_DEPTH in blob.cpp to test Jérôme's github pull request POV-Ray#358. Longer term aim is to drive all returned intersection depths from shape code to MIN_ISECT_DEPTH_RETURNED. The value is automatically derived from DBL setting and at double resolves to about 4.44089e-08. On the order of the square root of POV_DBL_EPSILON. Moving blob.cpp's inside test value INSIDE_TOLERANCE to POV_DBL_EPSILON over previous recent re-calculation. Over time plan is to move EPSILONs best nearer a double's step to POV_DBL_EPSILON. Cleaning up doxygen documentation added during recent solver related updates.
1 parent fab23d8 commit 4e2135d

File tree

4 files changed

+206
-115
lines changed

4 files changed

+206
-115
lines changed

source/base/configbase.h

Lines changed: 125 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -114,44 +114,6 @@
114114
#define POV_CPP11_SUPPORTED (__cplusplus >= 201103L)
115115
#endif
116116

117-
/// @}
118-
///
119-
//******************************************************************************
120-
///
121-
/// @name C++11 Constant Expression Support
122-
///
123-
/// The following macros and constant expression (constexpr) functions enable the set up of
124-
/// compile time typed contants.
125-
///
126-
/// References in addtion to the C++11 standard itself:
127-
/// * [sac10-constexpr.pdf](http://www.stroustrup.com/sac10-constexpr.pdf)
128-
/// * [n2235.pdf](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf)
129-
///
130-
/// @{
131-
132-
/// @def CX_XSTR(A)
133-
/// Macro converts preprocessor macro string to a contant string.
134-
///
135-
/// @note
136-
/// Itself using an macro internale macro called CX_STR(A).
137-
///
138-
#define CX_XSTR(A) CX_STR(A)
139-
#define CX_STR(A) #A
140-
141-
/// @def CX_STRCMP(A,B)
142-
/// constexpr function comparing two strings in compile time constant fashion.
143-
///
144-
/// @param[in] A First string.
145-
/// @param[in] B Second string.
146-
/// @return Integer 0 on matching strings and non zero integer otherwise.
147-
///
148-
constexpr int CX_STRCMP(char const* lhs, char const* rhs)
149-
{
150-
return (('\0' == lhs[0]) && ('\0' == rhs[0])) ? 0
151-
: (lhs[0] != rhs[0]) ? (lhs[0] - rhs[0])
152-
: CX_STRCMP( lhs+1, rhs+1 );
153-
}
154-
155117
/// @}
156118
///
157119
//******************************************************************************
@@ -358,9 +320,72 @@ constexpr int CX_STRCMP(char const* lhs, char const* rhs)
358320
#ifndef SNGL
359321
#define SNGL float
360322
#endif
323+
/// @}
324+
///
325+
//******************************************************************************
326+
///
327+
/// @name C++11 Constant Expression Support
328+
///
329+
/// The following macros and constant expression (constexpr) functions enable the set up of
330+
/// compile time typed contants.
331+
///
332+
/// References in addtion to the C++11 standard itself:
333+
/// * [sac10-constexpr.pdf](http://www.stroustrup.com/sac10-constexpr.pdf)
334+
/// * [n2235.pdf](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf)
335+
/// * [github constexpr function library](https://github.com/elbeno/constexpr)
336+
///
337+
/// @attention
338+
/// Do NOT use any CX_ prefixed function at runtime. Use them carefully at
339+
/// compile time. Currently, no error checking is done. Aim is to move burden for
340+
/// complex macro definitions from build systems like autotools, cmake, etc into C++
341+
/// itself where the C++11 standard supports it. If found to fly well in
342+
/// practice, will look to make any constant expression functions more robust.
343+
///
344+
/// @{
345+
346+
/// @def CX_STR(A)
347+
/// Macro used by @ref CX_XSTR(A) in conversion of definition to a string value.
348+
///
349+
/// @def CX_XSTR(A)
350+
/// Macro converts preprocessor macro string to a contant string.
351+
///
352+
/// @note
353+
/// Itself using an macro internal macro called CX_STR(A).
354+
///
355+
#define CX_XSTR(A) CX_STR(A)
356+
#define CX_STR(A) #A
357+
358+
static constexpr int CX_STRCMP(char const* lhs, char const* rhs); // Doxygen requires.
359+
/// constexpr function comparing two strings in compile time constant fashion.
360+
///
361+
/// @param[in] lhs First string.
362+
/// @param[in] rhs Second string.
363+
/// @return Integer 0 on matching strings and non zero integer otherwise.
364+
///
365+
static constexpr int CX_STRCMP(char const* lhs, char const* rhs)
366+
{
367+
return (('\0' == lhs[0]) && ('\0' == rhs[0])) ? 0
368+
: (lhs[0] != rhs[0]) ? (lhs[0] - rhs[0])
369+
: CX_STRCMP( lhs+1, rhs+1 );
370+
}
371+
372+
static constexpr POV_INT64 CX_IPOW(POV_INT64 base, int exp, POV_INT64 result = 1); // Doxygen requires.
373+
/// constexpr function implementing integer pow() in compile time constant fashion.
374+
///
375+
/// @note
376+
/// Optional third argument part of implementation. Call as follows: CX_IPOW(10,3).
377+
///
378+
/// @param[in] base
379+
/// @param[in] exp
380+
/// @param[in] result (do NOT specify on actual first call)
381+
/// @return Integer base raised to exponent.
382+
///
383+
static constexpr POV_INT64 CX_IPOW(POV_INT64 base, int exp, POV_INT64 result) {
384+
return exp < 1 ? result : CX_IPOW(base*base, exp/2, (exp % 2) ? result*base : result);
385+
}
361386

362387
/// @def PRECISE_FLOAT
363-
/// The foating-point data type to use within the polysolve() solver.
388+
/// Optionally more accurate foating-point data type to use within root solver related code.
364389
///
365390
/// Normally PRECISE_FLOAT will be set to @ref DBL. However, 'long double' is a
366391
/// precision guaranteed by the C++ standard to exist and to be at least of
@@ -371,6 +396,10 @@ constexpr int CX_STRCMP(char const* lhs, char const* rhs)
371396
/// data types. Recent GNU g++ compilers, for example, offer the __float128
372397
/// data type which coorresponds to the IEEE 754-2008 binary128 type.
373398
///
399+
/// The following functions support PRECISE_FLOAT:
400+
/// * polysolve(). Known to users as sturm.
401+
/// * solve_quadratic()
402+
///
374403
/// @note
375404
/// The setting is used to set internal 'constextr int PRECISE_DIG' and
376405
/// 'constexpr DBL PRECISE_EPSILON' typed values.
@@ -379,14 +408,10 @@ constexpr int CX_STRCMP(char const* lhs, char const* rhs)
379408
/// If @ref PRECISE_FLOAT is set to 'float', 'double' or 'long double', the C++11 standard
380409
/// itself defines via cfloat include the macros: FLT_DIG, DBL_DIG, LDBL_DIG, FLT_EPSILON,
381410
/// DBL_EPSILON, LDBL_EPSILON. These macro values are used to set PRECISE_DIG and
382-
/// PRECISE_EPSILON polysolve() values via the C++ constexpr mechanism.
383-
///
384-
/// @note
385-
/// Users access the polysolve() solver via the 'sturm' keyword though it's always
386-
/// used for polynomials of order 5 or more.
411+
/// PRECISE_EPSILON values via the C++ constexpr mechanism.
387412
///
388413
/// @attention
389-
/// polysolve() math with data types not run in hardware or with awkward bit sizes with
414+
/// Math with data types not run in hardware or with awkward bit sizes with
390415
/// respect to the running computer's data bus size will run substantially slower.
391416
///
392417
#ifndef PRECISE_FLOAT
@@ -410,6 +435,9 @@ constexpr int CX_STRCMP(char const* lhs, char const* rhs)
410435
///
411436
/// Where @ref PRECISE_FLOAT a C++11 standard floating point type this should be
412437
/// the default sqrt. It would be set to sqrtq if using GNU g++'s quadmath library.
438+
/// If using the inbuilt g++ __float128 capability, set to cast to and from (long double)
439+
/// to avoid the use of quadmath - though this of course effectively limits sqrt()
440+
/// accuracy to 'long double'.
413441
///
414442
#ifndef PRECISE_SQRT
415443
#define PRECISE_SQRT sqrt
@@ -435,8 +463,17 @@ constexpr int CX_STRCMP(char const* lhs, char const* rhs)
435463
#define PRECISE_EPSLN 1.92592994438724e-34
436464
#endif
437465

438-
/// @def PRECISE_DIG
439-
/// Internal 'constexpr int' value for maximum decimal digits for given @ref PRECISE_FLOAT.
466+
/// @var PRECISE_FLT
467+
/// A 'constexpr int' 0 when @ref PRECISE_FLOAT resolves to float type or !=0 otherwise.
468+
///
469+
/// @var PRECISE_DBL
470+
/// A 'constexpr int' 0 when @ref PRECISE_FLOAT resolves to double type or !=0 otherwise.
471+
///
472+
/// @var PRECISE_LDBL
473+
/// A 'constexpr int' 0 when @ref PRECISE_FLOAT resolves to long double type or !=0 otherwise.
474+
///
475+
/// @var PRECISE_DIG
476+
/// A 'constexpr int' maximum decimal digits given @ref PRECISE_FLOAT.
440477
///
441478
/// Set to C+11 standard value where defined and to @ref PRECISE_DIGITS otherwise.
442479
///
@@ -451,25 +488,48 @@ constexpr int PRECISE_DIG = PRECISE_FLT ?
451488
: DBL_DIG
452489
: FLT_DIG;
453490

454-
/// @def PRECISE_EPSILON
455-
/// Internal 'constexpr DBL' value*2.0 for minimum epsilon step for given @ref PRECISE_FLOAT.
491+
/// @var PRECISE_EPSILON
492+
/// A 'constexpr DBL' value for minimum epsilon step given @ref PRECISE_FLOAT.
456493
///
457-
/// Set to C+11 standard value where defined and to @ref PRECISE_EPSLN otherwise.
494+
/// Set to C+11 standard value*2.0 where defined and to @ref PRECISE_EPSLN*2.0 otherwise.
458495
///
459496
/// @note
460497
/// Using 2.0 multiplier due maths calculating coefficients for higher order polynomials
461498
/// introducing more than single bit/step error in practice.
462499
///
463-
464500
constexpr DBL PRECISE_EPSILON = PRECISE_FLT ?
465501
PRECISE_DBL ?
466502
PRECISE_LDBL ? PRECISE_EPSLN*2.0
467503
: LDBL_EPSILON*2.0
468504
: DBL_EPSILON*2.0
469505
: FLT_EPSILON*2.0;
470506

471-
/// @def POV_DBL_EPSILON
472-
/// Internal 'constexpr DBL' value for minimum epsilon step for given POV-Ray's @ref DBL.
507+
/// @var POV_DBL_IS_FLT
508+
/// A 'constexpr int' 0 when @ref DBL resolves to float type or !=0 otherwise.
509+
///
510+
/// @var POV_DBL_IS_DBL
511+
/// A 'constexpr int' 0 when @ref DBL resolves to double type or !=0 otherwise.
512+
///
513+
/// @var POV_DBL_IS_LDBL
514+
/// A 'constexpr int' 0 when @ref DBL resolves to long double type or !=0 otherwise.
515+
///
516+
/// @var POV_DBL_DIG
517+
/// A 'constexpr int' value for maximum decimal digits for given @ref DBL.
518+
///
519+
/// Set to C+11 standard value where defined and to @ref PRECISE_DIGITS otherwise.
520+
///
521+
constexpr int POV_DBL_IS_FLT = CX_STRCMP(CX_XSTR(DBL), "float");
522+
constexpr int POV_DBL_IS_DBL = CX_STRCMP(CX_XSTR(DBL), "double");
523+
constexpr int POV_DBL_IS_LDBL = CX_STRCMP(CX_XSTR(DBL), "long double");
524+
constexpr int POV_DBL_DIG = POV_DBL_IS_FLT ?
525+
POV_DBL_IS_DBL ?
526+
POV_DBL_IS_LDBL ? PRECISE_DIGITS
527+
: LDBL_DIG
528+
: DBL_DIG
529+
: FLT_DIG;
530+
531+
/// @var POV_DBL_EPSILON
532+
/// A 'constexpr DBL' value for minimum epsilon step for given POV-Ray's @ref DBL.
473533
///
474534
/// Set to C+11 standard value*2.0 where defined and to @ref PRECISE_EPSLN*2.0 otherwise.
475535
///
@@ -481,17 +541,25 @@ constexpr DBL PRECISE_EPSILON = PRECISE_FLT ?
481541
/// Using 2.0 multiplier due maths calculating coefficients for higher order polynomials
482542
/// introducing more than single bit/step error in practice.
483543
///
484-
constexpr int POV_DBL_IS_FLT = CX_STRCMP(CX_XSTR(DBL), "float");
485-
constexpr int POV_DBL_IS_DBL = CX_STRCMP(CX_XSTR(DBL), "double");
486-
constexpr int POV_DBL_IS_LDBL = CX_STRCMP(CX_XSTR(DBL), "long double");
487-
488544
constexpr DBL POV_DBL_EPSILON = POV_DBL_IS_FLT ?
489545
POV_DBL_IS_DBL ?
490546
POV_DBL_IS_LDBL ? PRECISE_EPSLN*2.0
491547
: LDBL_EPSILON*2.0
492548
: DBL_EPSILON*2.0
493549
: FLT_EPSILON*2.0;
494550

551+
552+
/// @var MIN_ISECT_DEPTH_RETURNED
553+
/// A 'constexpr DBL' value below which roots from primitive objects are not returned.
554+
///
555+
/// The value will track @ref DBL float type and is very roughly the square root
556+
/// of the determined POV_DBL_EPSILON. The plan is to migrate base shapes to
557+
/// this single value instead of the many different thresholds used today.
558+
/// Aiming for both more accuracy and something which automatically adjust to
559+
/// the DBL type used.
560+
///
561+
constexpr DBL MIN_ISECT_DEPTH_RETURNED = POV_DBL_EPSILON*(DBL)CX_IPOW(10,POV_DBL_DIG/2+1);
562+
495563
/// @}
496564
///
497565
//******************************************************************************

source/core/math/polynomialsolver.cpp

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -50,57 +50,64 @@ namespace pov
5050
* Local preprocessor defines
5151
******************************************************************************/
5252

53-
/// @def FUDGE_FACTOR2
54-
/// Value defining how close the quartic equation is to being a square
55-
/// of a quadratic in the OLD unused solve_quartic version kept for testing.
53+
/// @var FUDGE_FACTOR2
54+
/// @brief const DBL value defining how close quartic equation is to being a square
55+
/// of a quadratic.
5656
///
5757
/// @note
5858
/// The closer this can get to zero before roots disappear, the less the chance
5959
/// you will get spurious roots.
6060
///
61+
/// @attention
62+
/// Used only in the old unused version of solve_quartic().
63+
// In other words not used.
64+
///
6165
const DBL FUDGE_FACTOR2 = -1.0e-5;
6266

63-
/// @def FUDGE_FACTOR3
64-
/// Similar to @ref FUDGE_FACTOR2 at a later stage of the algebraic solver. Also
65-
/// long used only in the old kept for testing version of solve_quartic().
67+
/// @var FUDGE_FACTOR3
68+
/// @brief const DBL value similar to @ref FUDGE_FACTOR2 at a later stage of the
69+
/// algebraic solver.
6670
///
67-
/// @note
71+
/// @ref FUDGE_FACTOR2 and @ref FUDGE_FACTOR3 have been defined so that quartic
72+
/// equations will properly render on fpu/compiler combinations that only have
73+
/// 64 bit IEEE precision. Do not arbitrarily change any of these values.
6874
///
69-
/// @ref FUDGE_FACTOR2 and @ref FUDGE_FACTOR3 have been defined so that quartic
70-
/// equations will properly render on fpu/compiler combinations that only have
71-
/// 64 bit IEEE precision. Do not arbitrarily change any of these values.
75+
/// If you have a machine with a proper fpu/compiler combo - like a Mac with a
76+
/// 68881, then use the native floating format (96 bits) and tune the values for
77+
/// a little less tolerance: something like: factor2 = -1.0e-7, factor3 =
78+
/// 1.0e-10. Twenty five years later the reality is still double accuracy
79+
/// due use of fastmath (not IEEE compliant) compiling, use of SSE Fused
80+
/// Multiply Add instructions, etc.
7281
///
73-
/// If you have a machine with a proper fpu/compiler combo - like a Mac with a
74-
/// 68881, then use the native floating format (96 bits) and tune the values for
75-
/// a little less tolerance: something like: factor2 = -1.0e-7, factor3 =
76-
/// 1.0e-10. Twenty five years later the reality is still double accuracy
77-
/// due use of fastmath (not IEEE compliant) compiling, use of SSE Fused
78-
/// Multiply Add instructions, etc.
82+
/// @attention
83+
/// Used only in the old unused version of solve_quartic().
84+
// In other words not used.
7985
///
8086
const DBL FUDGE_FACTOR3 = 1.0e-7;
8187

82-
/// @def TWO_M_PI_3
83-
/// Value used in solve_cubic() equal to 2.0 * pi / 3.0.
88+
/// @var TWO_M_PI_3
89+
/// const DBL value used in solve_cubic() equal to 2.0 * pi / 3.0.
8490
///
8591
const DBL TWO_M_PI_3 = 2.0943951023931954923084;
8692

87-
/// @def FOUR_M_PI_3
88-
/// Value used in solve_cubic() equal to 4.0 * pi / 3.0.
93+
/// @var FOUR_M_PI_3
94+
/// const DBL value used in solve_cubic() equal to 4.0 * pi / 3.0.
8995
///
9096
const DBL FOUR_M_PI_3 = 4.1887902047863909846168;
9197

92-
/// @def MAX_ITERATIONS
93-
/// Max number of polysolve sturm chain based bisections.
98+
/// @var MAX_ITERATIONS
99+
/// const int max number of polysolve sturm chain based bisections.
94100
///
95101
/// @note
96102
/// regula_falsa() uses twice this value internally as it can be
97103
/// quite slow to converge in the worst case.
98104
///
99105
const int MAX_ITERATIONS = 65;
100106

101-
/// @def SBISECT_MULT_ROOT_THRESHOLD
102-
/// Value below which multiple roots ignored in sturm chained based bisection
103-
/// and a sigle root at the middle of the current interval is returned.
107+
/// @var SBISECT_MULT_ROOT_THRESHOLD
108+
/// const @ref PRECISE_FLOAT value below which multiple roots ignored in sturm
109+
/// chained based bisection and a single root at the middle of the current
110+
/// interval is returned.
104111
///
105112
/// @note
106113
/// Rays near tangent to surface create extremely close roots and instability
@@ -110,8 +117,9 @@ const int MAX_ITERATIONS = 65;
110117
///
111118
const PRECISE_FLOAT SBISECT_MULT_ROOT_THRESHOLD = (PRECISE_FLOAT)1e-6;
112119

113-
/// @def REGULA_FALSA_THRESHOLD
114-
/// Threshold below which regula_falsa function is tried when there is a single root.
120+
/// @var REGULA_FALSA_THRESHOLD
121+
/// const @ref PRECISE_FLOAT threshold below which regula_falsa function is tried
122+
/// when there is a single root.
115123
///
116124
/// @note
117125
/// Ray interval max_value - min_value threshold below which regula_falsa
@@ -127,19 +135,20 @@ const PRECISE_FLOAT SBISECT_MULT_ROOT_THRESHOLD = (PRECISE_FLOAT)1e-6;
127135
///
128136
const PRECISE_FLOAT REGULA_FALSA_THRESHOLD = (PRECISE_FLOAT)1.0;
129137

130-
/// @def RELERROR
131-
/// Smallest relative error along the ray when using the polysolve(), sturm
132-
/// chain bisection / regula-falsi method.
138+
/// @var RELERROR
139+
/// const @ref PRECISE_FLOAT smallest relative error along the ray when using
140+
/// the polysolve(), sturm chain bisection / regula-falsi method.
133141
///
134142
const PRECISE_FLOAT RELERROR = (PRECISE_FLOAT)1.0e-12;
135143

136-
/// @def SMALL_ENOUGH
137-
/// Used to filter determinant value in solve_quadratic() in an unusual way.
138-
/// Used in solve_quartic() to filter values ahead of the trailing quadratics.
144+
/// @var SMALL_ENOUGH
145+
/// const @ref DBL value used to filter determinant value in older
146+
/// solve_quadratic() in an unusual way causing artifacts. Used too in
147+
/// solve_quartic() to filter values ahead of the trailing quadratics.
139148
///
140149
/// @todo
141150
/// Suspect value is larger than it should really be and very likely should
142-
/// not be used at all in solve_quadratic() as it is.
151+
/// not be used at all in solve_quartic() as it is.
143152
///
144153
const DBL SMALL_ENOUGH = 1.0e-10;
145154

0 commit comments

Comments
 (0)