Skip to content

Commit 761dd0b

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 af78a9b commit 761dd0b

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
@@ -113,44 +113,6 @@
113113
#define POV_CPP11_SUPPORTED (__cplusplus >= 201103L)
114114
#endif
115115

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

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

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

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

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

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

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)