黑客数值分析指南

2021-03-20 09:14:24

考虑以下程序:#包括< cmath> #包括< stdio.h> int main(){double x = 12e-9;双c = cos(x);双倍one_sub_c = 1 - c;双邻接= x * x;双yhat = one_sub_c / denom; Printf(" x:%20.16f \ n"" cx:%20.16f \ n"" one_sub_c:%20.16f \ n""否定: %20.16f \ n"" yhat:%20.16f \ n",x,c,one_sub_c,denom,yhat); }

产生输出:这显然是错误的,因为我们知道(1 - cos⁡x)/ x 2)≤1/ 2(1- \ cos x)/ x ^ 2)\ leq 1/2(1 - cos x)/ x 2)≤1/ 2.此可怕结果的原因是:我们知道Cos⁡X\ cos x cosx到高精度,因为xxx是一些固定数量。

1 - COS⁡x 1 - \ cos x 1 - cos x将cos⁡x\ cos x cosx中的错误转换为其值。

1 - COS⁡x 1 - \ cos x 1 - cos x只有一个重要人物。

一般:x≡1+εorgrantεy≡1 - x =ε值的ε\ begin {对齐}& x \ Equiv 1 + \ epsilon \ text {orground $ \ epsilon $} \\ & Y \ Equiv 1 - x = x = epsilon \文本{order $ \ epsilon $} \\\ end {对齐} x≡1+εor er oεy∈1 - x =ε值ε

也就是说,减去彼此接近的值(在这种情况下,11 1和x x x)将误差顺序转换为值级。或者,它将较早的错误带入诸如价值的景点。我们可以考虑减法:x = a - b; x ^ = a ^ - b ^ a ^ = a(1 +δa)b ^ = b(1 +δb)| x-x ^ x | = | - aδa-bδba-b | = | - Aδa-bδb| A-B | = |δa+bδb| - b |≤Max⁡(|δa|,|δb|)(| a | + | b |)| A - B | \ Begin {对齐}& x = a - b; \帽子x = \帽子a - \ hat b \\& \ hat a = a(1 + \ delta a)\\&at att b = b(1 + \ delta b)\\&左| \ frac {x - \ hat x} {x} \右| \\& = \左手| \ frac {-a \ delta a - b \ delta b} {a - b} \右| \\& = \ frac {| -a \ delta a - b \ delta b |} {| a - b |} \\& = \ frac {| a \ delta a + b \ delta b |}}} { a - b |} \\& \&leq \ frac {\ max(| \ delta a |,| \ delta b |)(| a | + | b |)} {| a - b |} \ end {对齐} x = a - b;的x ^ = a ^ - B ^一个^ =(1 +ΔA)B ^ = B(1 +ΔB)| | | | | XX - 的x ^ | | | | | = | | | | | A - B - aδa-bδb| | | | = | a - b | | - aδa-bδb|α - b | aδa+bδ B |≤| A - B | MAX(|δa|,|δb|)(| A | + | B |)

当| A - B |«| A | + | B | | A - B | \ ll | A | + | B | | A - B |«| A | + | B |:即,当减法中有很重的消除时计算x x x。 #包括< cmath> #包括< stdio.h> int main(){double x = 1000; for(int i = 0; i< 60; ++ i){x = sqrt(x); for(int i = 0; i< 60; ++ i){x = x * x; printf(" x:%10.20f \ n",x); }

这会产生输出:即使功能是身份函数,答案崩溃为1.发生了什么?评估此功能的一种方法如下:双F(双x){返回x == 0? 1 :( Pow(M_E,x) - 1)/ x; }

这可能在分子中遭受灾难性的消除。当x x x接近0 0时,e x e ^ x e x接近1,而e x - 1 e ^ x - 1 e x-1将在e x e ^ x e x中放大错误。双f(双x){const double y = pow(m_e,x);返回y == 1? 1 :( y - 1)/ log(y); }

这种算法似乎疯狂,但它的见解'我们可以证明错误取消!这个想法是(y-1)(y - 1)(y - 1)也不是log⁡y\ log y lo gy特别好,在它们中累积的误差几乎完全抵消,留出了很好的价值:假设y ^ = 1 1 = y ^≡ex(1 +δ)log⁡1= log⁡(ex)+ log⁡(1 +δ)x = - log⁡(1 +Δ)x = - δ+ o(δ 2)\文本{假设$ \ hat y = 1 $} \\ 1 = \ hat y \ Equiv E ^ x(1 + \ delta)\\\ log 1 = log(e ^ x)+ \ log(1 + \ delta)\\ x = - \ log(1 + \ delta)\\ x = - \ delta + o(\ delta ^ 2)假设y ^ = 1 1 = y ^ ex(1 +Δ) lo g 1 = lo g(ex)+ lo g(1 +δ)x = - lo g(1 +δ)x = - δ+ o(δ2)

如果Y ^≠1\ hat y \ neq 1 y ^= 1:f ^ =(y ^ - 1)/ log⁡y^ =(1 +ε3)(y ^ - 1)(1 +ε+ 1)/(日志⁡y ^(1 +ε2))\ hat f =(\ hat y-1)/ \ log {\ hat y} =(1+ \ epsilon_3)(\ hat y-1)(1 + \ epsilon + 1)/(\ log \ hat y(1 + \ epsilon_2))f ^ =(y ^ - 1)/ lo gy ^ =(1 +ε3)(y ^ - 1 )(1 +ε+ 1)/(lo gy ^(1 +ε2))

而不是将+0和-0作为不同的数值,而不是将其符号位视为辅助变量,该辅助变量传达了一个关于任何按0作为其值的数字变量的信息(或错误信息)。

我们在IEEE-754中有两种类型的零,+0和-0。这些在某些情况下使用。最着名的是1 / + 0 = +∞1/ + 0 = +秒1 / + 0 = +,而1 / - 0 = - ∞1/ -0 = - \ infty 1 / - 0 = - ∞。在这里,我们继续讨论一些复杂的分析考虑因素。所以。如果应用程序员要实现复杂算法的IEEE风格的充分利益,则编译器和运行时库的实施者承担了沉重的关注。如果只是为了向实施者保证他们的惯用,那么这种福利应该在这里讨论。

- 1 + 0 i = + 0 + i - 1 - 0 i = + 0 - i \ sqrt {-1 + 0 i} = +0 + i \\\ sqrt {-1 - 0 i} = +0 - i \\ - 1 + 0 i = + 0 + i - 1 - 0 i = + 0 - i

这些将确保z * =(z)* \ sqrt {z *} =(\ sqrt {z})* z * =(z)*:copysign(1,+ 0)= + 1 copysign(1, - 0)= - 1 \ texttt {copysign}(1,+0)= +1 \\\ texttt {copysign}(1,-0)= -1 \\ copysign(1,+ 0)= + 1 copySign( 1, - 0)= - 1

这些将确保CopySign(x,1 / x)= x \ texttt {copysign}(x,1 / x)= x copysign(x,1 / x)= x x =±x = \ pm \ infty x =±∞。提供了一个例子,其中两个限制:f(x + i 0)= lim≠y→0 - f(x + iy)f(x + i 0)= lim y→0 - f(x + iy)\开始{对齐}& f(x + i0)= \ lim_ {y \ lightarrow 0-} f(x + iy)\\& f(x + i0)= \ lim_ {y \ lightarrow 0-} f( x + iy)\\\结束{对齐} f(x + i 0)= y→0 - lim f(x + iy)f(x + i 0)= y→0 - lim f(x + IY)

复杂函数的主要分支是选择复杂功能的一个分支的方法,这往往是多值的。古典示例是参数函数,其中arg⁡(Reiθ=θ\ arg(re ^ {i \ theta} = \ theta ar g(Reiθ=θ。但是,这是模糊的:我们可以映射θ↦θ+ 2π\ theta \ mapsto \ theta + 2 \piθ↦θ+2π且仍然具有相同的复数。所以,我们需要修复一些标准。我们通常选择&#34;分支&#34;其中0≤ θ&lt;2π0\ leq \ theta&lt; 2 \ pi0≤θ<θ<θ&lt; 2.一般来说,我们需要仔细处理不连续功能的功能发生的事情。值得被破坏的是盲目的信仰代数的力量。我们不应该相信所有描述相同复杂的分析功能的等效表达式可以单独识别代数手段,即使相对简单的表达式也是唯一考虑的表达式。