在c ++中norm,复数数字c的定义为abs(c)^2.这意味着它re(c)^2+im(z)^2.
这是实施:
template<bool>
struct _Norm_helper
{
template<typename _Tp>
static inline _Tp _S_do_it(const complex<_Tp>& __z)
{
const _Tp __x = __z.real();
const _Tp __y = __z.imag();
return __x * __x + __y * __y;
}
};
template<>
struct _Norm_helper<true>
{
template<typename _Tp>
static inline _Tp _S_do_it(const complex<_Tp>& __z)
{
_Tp __res = std::abs(__z);
return __res * __res;
}
};
Run Code Online (Sandbox Code Playgroud)
为什么有人想要使用第二个实现?
第一个显然更快,因为它不使用abs,sqrt涉及的地方.
如果我们研究一下实施情况,我们会在那里找到答案,
// 26.2.7/5: norm(__z) returns the squared magnitude of __z.
// As defined, norm() is -not- a norm is the common mathematical
// sens used in numerics. The helper class _Norm_helper<> tries to
// distinguish between builtin floating point and the rest, so as
// to deliver an answer as close as possible to the real value.
template<bool>
struct _Norm_helper
{
template<typename _Tp>
static inline _Tp _S_do_it(const complex<_Tp>& __z)
{
const _Tp __x = __z.real();
const _Tp __y = __z.imag();
return __x * __x + __y * __y;
}
};
template<>
struct _Norm_helper<true>
{
template<typename _Tp>
static inline _Tp _S_do_it(const complex<_Tp>& __z)
{
_Tp __res = std::abs(__z);
return __res * __res;
}
};
template<typename _Tp>
inline _Tp
norm(const complex<_Tp>& __z)
{
return _Norm_helper<__is_floating<_Tp>::__value
&& !_GLIBCXX_FAST_MATH>::_S_do_it(__z);
}
Run Code Online (Sandbox Code Playgroud)
norm因此,当应用于内置浮点类型的值(即float、double、long double或__float128按照 GCC 4.8.1)并且-fast-math未设置该选项时,将调用第二个实现。这样做是为了符合norm定义为 的标准定义the squared magnitude of z。
由于舍入误差,z.real()*z.real() + z.imag()*z.imag()不等于abs(z)*abs(z),因此第一个版本将与规范措辞不一致(这可能表明规范存在问题)。为了更容易理解为什么措辞很重要,请考虑期望的代码norm(x) / abs(x) = x。当然,这是一个糟糕的代码,但标准在某种意义上保证了这应该是正确的。
然而,一旦设置了 FAST_MATH 或complex专门用于非内置类型,该标准就不再具有其威力(因为它明确表示该行为未定义)并且实现将下降到第一个实现,可以说是1更快、更精确。
1) ) 它实际上取决于许多因素(例如是否使用内置内在函数)和 yada,yada,yada,所以让我们对这一说法持保留态度。
| 归档时间: |
|
| 查看次数: |
1384 次 |
| 最近记录: |