au
au copied to clipboard
Compute magnitudes in the "real part" of a type
A Magnitude
is defined to be a real number. But users can ask for
its value in, say, std::complex<int>
(either explicitly or
implicitly). This is a problem, because in computing that value, we
check for overflow, which involves less-than comparisons... but complex
numbers are not ordered, so there is no meaningful sense of <
!
To fix this, we introduce the notion of RealPart<T>
, a type trait that
gives a type related to T
that does have a notion of comparability.
(Since Magnitude
is defined to be a real number, calling it "real
part" is a good fit.) RealPart<T>
is just T
in almost all cases,
but it becomes "the type of T{}.real()
" whenever that exists. This
lets us support both std::complex
and complex number types from other
libraries.
The core of the fix was to make sure all of our Magnitude
operations
are taking place in RealPart<T>
rather than T
. This basically boils
down to the call to base_power_value
, and the implementations for
SafeCastingChecker
. We also use the real type throughout the
:apply_magnitude
targets, for two reasons. First, there's an actual
bug in clang related to complex-complex division. Second, it should be
faster at runtime to only divide by the real part.
This change also has knock-on effects for implicit conversion policy. It
turns out the old implementation of CoreImplicitConversionPolicy
was
always silently assuming that the type was already a real number type.
Therefore, we rename it by adding an AssumingReal
suffix on the end.
The new CoreImplicitConversionPolicy
passes RealPart<Rep>
along to
this, after first checking for a new pitfall to guard against: namely,
implicitly converting a complex type to a real type.
Fixes #228.