Codac builds today against the GAOL 4.2 of Frédéric Goualard. This issue summarizes what a code using GAOL has to adapt to move to GAOL 4.3.2 (branch master of Jordan08/GAOL) or to GAOL v5 (branch MATH-CORE). GAOL 4.3.2 is a direct ancestor of GAOL v5, so everything in the first section is included in the second. Each change is detailed, with its reasons and its measurements, in doc/differences.md, and the manual of GAOL v5 has a chapter Moving a program from GAOL 4 to GAOL v5.
GAOL 4.2 → GAOL 4.3.2 (branch master)
No source change is needed: gaol/gaol.h still opens namespace gaol, and the headers, types and functions are unchanged. C++11 is required (the throw() exception specifications are gone). Recompiling is enough.
Build and link
- The patch IBEX applies to GAOL (
gaol-4.2.3alpha0.all.all.patch) is integrated and must not be applied: the FPU is initialised with fesetenv(), the macro opposite() is renamed gaol_opposite(), and interval::midpoint() and operator<< set the rounding direction back upward.
- A CMake build exists:
find_package(gaol) gives the target gaol::gaol, which carries the flags of interval arithmetic; mathlib is built with GAOL from 3rd/mathlib and exported as gaol::ultim. The option GAOL_FIND_MATHLIB=OFF builds and installs mathlib with GAOL even where one is installed, for Codac's build, which expects libultim and MathLib.h under the prefix it gives. Each build installs a gaol.pc for pkg-config.
- The rounding direction is no longer the caller's business: each operation sets it upward itself, and leaves it upward. A code computing its own floating point to nearest between GAOL calls either accepts that, or builds GAOL with
GAOL_PRESERVE_ROUNDING, which — unlike the "preserve" of GAOL 4 — really restores the caller's direction, SSE register included.
gaol::intervalf and gaol::interval2f are compiled only with GAOL_FLOAT_INTERVALS (Codac uses neither).
gaol/gaol_config.h refuses the configurations that give wrong bounds (Clang for 32-bit ARM, MinGW-w64 older than 12, /fp:fast…).
Results that change
Regression baselines may move; two idioms have to be audited:
- ⚠️ The intersection of disjoint intervals is the empty set
[NaN, NaN] rather than reversed bounds ([3, 2]): code reading the bounds of an empty intersection, or testing left() > right(), must go through is_empty().
- ⚠️
width() of the empty set is NaN rather than −1.
- Tighter bounds:
sin/cos/tan within one double of the tightest at every magnitude, integer powers and nth roots proved from exact products, sqrt the tightest, exp(0) = 1 and log(1) = 0 exact, pow(x, -n) without overflow.
atan2() is implemented (it raised unavailable_feature_error).
- The constructors give the empty set for
interval(+oo), interval(2, 1) and NaN bounds, as IBEX's patch imposed.
pow(I, double) no longer truncates the exponent to an int, and pow(I, J) keeps the negative part of the base for an integer exponent only — the fix ported from Codac (74086cc), which Codac can drop from its own wrapper.
nth_root of an odd order is defined on the whole real line (the rootn of IEEE 1788-2015); log of an interval holding no positive number is empty; the comparisons follow Tables 10.3 and 10.4 of IEEE 1788-2015 for empty sets and infinite bounds (certainly_leq() is true when either interval is empty); a zero bound times an infinite one counts as 0.
- Input/output: the interval literals of IEEE 1788-2015 are read (
[empty], [1,], 0x1.3p-1, 3.56?1; "[inf]" is the empty set), numbers are read exactly on every C library, and the decimal output is rounded outward on every C library.
- Added or fixed:
rad() and mid_rad(), mid(), hausdorff(), div_rel(), invabs_rel(), uipow() exported.
GAOL 4.3.2 → GAOL v5 (branch MATH-CORE)
All of the above, plus real source adaptations:
gaol/gaol.h no longer opens namespace gaol. Add using namespace gaol;, or name gaol::interval; open exactly one of gaol and gaol_ieee1788, their pow being ambiguous with both. Code that already qualifies gaol:: compiles unchanged. The symbols of the library name gaol_core: every client is compiled again, there is no binary compatibility.
== and != on intervals are removed, with the possibly relations (possibly_eq()…), certainly_eq(), certainly_neq() and the option --enable-relations. A program compares intervals with set_eq(), set_disjoint() and !set_disjoint(); <, <=, > and >= are the certainly relations in every build. A leftover == stops the compilation, so nothing passes silently.
- No mathematical library is left to find, build or link: mathlib is gone, CORE-MATH is compiled into
libgaol. For Codac: GAOL_FIND_MATHLIB, gaol::ultim, libultim and MathLib.h no longer exist; gaol::gaol is linked alone (PUBLIC for a library whose headers include GAOL's, so that its own users get the flags). GAOL can also be brought in by FetchContent, with no network access beyond its sources.
- The
hexa output format writes interval literals ([0x1.999999999999ap-4, …]), read back bit for bit as IEEE 1788-2015 requires, rather than the sixteen raw hexadecimal digits of each double. The decimal formats and the default one are unchanged.
- One grammar reads every string:
"1+[1,2]" and "[cos([0,1]), 2]" are read where GAOL 4 refused them, the reader knows every function of GAOL, gaol::textToInterval() is added, and gaol_ieee1788::textToInterval() reads the names of the standard (pown, rootn, sinPi…). Several threads can read strings at once, where GAOL 4 crashed.
- New operations:
exp2, log2, exp10, log10, fifteen functions of Table 10.5 (expm1, log1p, hypot, rsqrt, sinpi, atan2pi…), fma, cancelMinus/cancelPlus, sign, trunc, round_ties_to_even/_away, and the namespace gaol_ieee1788, which gives every operation the name, the argument order and the semantics of IEEE 1788-2015.
- Tightest bounds everywhere: the elementary functions are correctly rounded (CORE-MATH) and exact where their value is a double, rather than one double beyond. Expected bounds hard-coded in tests may move by one or two doubles, always inward.
- With C++17,
GAOL_NODISCARD warns on an ignored result (sqrt(I); alone).
Performance, in passing: GAOL v5 is markedly faster where GAOL 4 suffered — the elementary functions are 3 to 10 times faster with MinGW-w64 and Visual C++, the rounding direction being written to the x86 control registers rather than through fesetround().
Summary for Codac
- To 4.3.2: recompile against it, stop applying local fixes GAOL now carries (the
pow fix, IBEX's patch), and audit the two empty-set idioms (width() == -1, bounds of an empty intersection).
- To v5: additionally add
using namespace gaol; where the code counted on gaol.h opening it, replace ==/!= and the possibly relations with the set relations, and remove mathlib from the build — libgaol is the only library left to link.
Codac builds today against the GAOL 4.2 of Frédéric Goualard. This issue summarizes what a code using GAOL has to adapt to move to GAOL 4.3.2 (branch
masterof Jordan08/GAOL) or to GAOL v5 (branchMATH-CORE). GAOL 4.3.2 is a direct ancestor of GAOL v5, so everything in the first section is included in the second. Each change is detailed, with its reasons and its measurements, in doc/differences.md, and the manual of GAOL v5 has a chapter Moving a program from GAOL 4 to GAOL v5.GAOL 4.2 → GAOL 4.3.2 (branch
master)No source change is needed:
gaol/gaol.hstill opens namespacegaol, and the headers, types and functions are unchanged. C++11 is required (thethrow()exception specifications are gone). Recompiling is enough.Build and link
gaol-4.2.3alpha0.all.all.patch) is integrated and must not be applied: the FPU is initialised withfesetenv(), the macroopposite()is renamedgaol_opposite(), andinterval::midpoint()andoperator<<set the rounding direction back upward.find_package(gaol)gives the targetgaol::gaol, which carries the flags of interval arithmetic; mathlib is built with GAOL from3rd/mathliband exported asgaol::ultim. The optionGAOL_FIND_MATHLIB=OFFbuilds and installs mathlib with GAOL even where one is installed, for Codac's build, which expectslibultimandMathLib.hunder the prefix it gives. Each build installs agaol.pcfor pkg-config.GAOL_PRESERVE_ROUNDING, which — unlike the "preserve" of GAOL 4 — really restores the caller's direction, SSE register included.gaol::intervalfandgaol::interval2fare compiled only withGAOL_FLOAT_INTERVALS(Codac uses neither).gaol/gaol_config.hrefuses the configurations that give wrong bounds (Clang for 32-bit ARM, MinGW-w64 older than 12,/fp:fast…).Results that change
Regression baselines may move; two idioms have to be audited:
[NaN, NaN]rather than reversed bounds ([3, 2]): code reading the bounds of an empty intersection, or testingleft() > right(), must go throughis_empty().width()of the empty set is NaN rather than −1.sin/cos/tanwithin one double of the tightest at every magnitude, integer powers and nth roots proved from exact products,sqrtthe tightest,exp(0) = 1andlog(1) = 0exact,pow(x, -n)without overflow.atan2()is implemented (it raisedunavailable_feature_error).interval(+oo),interval(2, 1)and NaN bounds, as IBEX's patch imposed.pow(I, double)no longer truncates the exponent to an int, andpow(I, J)keeps the negative part of the base for an integer exponent only — the fix ported from Codac (74086cc), which Codac can drop from its own wrapper.nth_rootof an odd order is defined on the whole real line (therootnof IEEE 1788-2015);logof an interval holding no positive number is empty; the comparisons follow Tables 10.3 and 10.4 of IEEE 1788-2015 for empty sets and infinite bounds (certainly_leq()is true when either interval is empty); a zero bound times an infinite one counts as 0.[empty],[1,],0x1.3p-1,3.56?1;"[inf]"is the empty set), numbers are read exactly on every C library, and the decimal output is rounded outward on every C library.rad()andmid_rad(),mid(),hausdorff(),div_rel(),invabs_rel(),uipow()exported.GAOL 4.3.2 → GAOL v5 (branch
MATH-CORE)All of the above, plus real source adaptations:
gaol/gaol.hno longer opens namespacegaol. Addusing namespace gaol;, or namegaol::interval; open exactly one ofgaolandgaol_ieee1788, theirpowbeing ambiguous with both. Code that already qualifiesgaol::compiles unchanged. The symbols of the library namegaol_core: every client is compiled again, there is no binary compatibility.==and!=on intervals are removed, with the possibly relations (possibly_eq()…),certainly_eq(),certainly_neq()and the option--enable-relations. A program compares intervals withset_eq(),set_disjoint()and!set_disjoint();<,<=,>and>=are the certainly relations in every build. A leftover==stops the compilation, so nothing passes silently.libgaol. For Codac:GAOL_FIND_MATHLIB,gaol::ultim,libultimandMathLib.hno longer exist;gaol::gaolis linked alone (PUBLICfor a library whose headers include GAOL's, so that its own users get the flags). GAOL can also be brought in byFetchContent, with no network access beyond its sources.hexaoutput format writes interval literals ([0x1.999999999999ap-4, …]), read back bit for bit as IEEE 1788-2015 requires, rather than the sixteen raw hexadecimal digits of each double. The decimal formats and the default one are unchanged."1+[1,2]"and"[cos([0,1]), 2]"are read where GAOL 4 refused them, the reader knows every function of GAOL,gaol::textToInterval()is added, andgaol_ieee1788::textToInterval()reads the names of the standard (pown,rootn,sinPi…). Several threads can read strings at once, where GAOL 4 crashed.exp2,log2,exp10,log10, fifteen functions of Table 10.5 (expm1,log1p,hypot,rsqrt,sinpi,atan2pi…),fma,cancelMinus/cancelPlus,sign,trunc,round_ties_to_even/_away, and the namespacegaol_ieee1788, which gives every operation the name, the argument order and the semantics of IEEE 1788-2015.GAOL_NODISCARDwarns on an ignored result (sqrt(I);alone).Performance, in passing: GAOL v5 is markedly faster where GAOL 4 suffered — the elementary functions are 3 to 10 times faster with MinGW-w64 and Visual C++, the rounding direction being written to the x86 control registers rather than through
fesetround().Summary for Codac
powfix, IBEX's patch), and audit the two empty-set idioms (width() == -1, bounds of an empty intersection).using namespace gaol;where the code counted ongaol.hopening it, replace==/!=and the possibly relations with the set relations, and remove mathlib from the build —libgaolis the only library left to link.