-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path11_power.html
665 lines (632 loc) · 52.3 KB
/
11_power.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>11 求幂 — THE END of ERROR - Unum Computing 0.1 documentation</title>
<link rel="stylesheet" href="_static/material-design-lite-1.3.0/material.blue-deep_orange.min.css" type="text/css" />
<link rel="stylesheet" href="_static/sphinx_materialdesign_theme.css" type="text/css" />
<link rel="stylesheet" href="_static/fontawesome/all.css" type="text/css" />
<link rel="stylesheet" href="_static/fonts.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/basic.css" />
<link rel="stylesheet" type="text/css" href="_static/d2l.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/sphinx_highlight.js"></script>
<script src="_static/d2l.js"></script>
<script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="12 其他重要的一元运算" href="12_other_important_unary_ops.html" />
<link rel="prev" title="10 乘法和除法" href="10_mul_div.html" />
</head>
<body>
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header mdl-layout--fixed-drawer"><header class="mdl-layout__header mdl-layout__header--waterfall ">
<div class="mdl-layout__header-row">
<nav class="mdl-navigation breadcrumb">
<a class="mdl-navigation__link is-active">11 求幂</a>
</nav>
<div class="mdl-layout-spacer"></div>
<nav class="mdl-navigation">
<form class="form-inline pull-sm-right" action="search.html" method="get">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--expandable mdl-textfield--floating-label mdl-textfield--align-right">
<label id="quick-search-icon" class="mdl-button mdl-js-button mdl-button--icon" for="waterfall-exp">
<i class="material-icons">search</i>
</label>
<div class="mdl-textfield__expandable-holder">
<input class="mdl-textfield__input" type="text" name="q" id="waterfall-exp" placeholder="Search" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</div>
</div>
<div class="mdl-tooltip" data-mdl-for="quick-search-icon">
Quick search
</div>
</form>
<a id="button-show-source"
class="mdl-button mdl-js-button mdl-button--icon"
href="_sources/11_power.rst.txt" rel="nofollow">
<i class="material-icons">code</i>
</a>
<div class="mdl-tooltip" data-mdl-for="button-show-source">
Show Source
</div>
</nav>
</div>
<div class="mdl-layout__header-row header-links">
<div class="mdl-layout-spacer"></div>
<nav class="mdl-navigation">
<a class="mdl-navigation__link" href="https://github.com/jszheng/TheEndOfError">
<i class="fab fa-github"></i>
Github
</a>
</nav>
</div>
</header><header class="mdl-layout__drawer">
<!-- Title -->
<span class="mdl-layout-title">
<a class="title" href="index.html">
<span class="title-text">
THE END of ERROR - Unum Computing
</span>
</a>
</span>
<div class="globaltoc">
<span class="mdl-layout-title toc">Table Of Contents</span>
<nav class="mdl-navigation">
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="Preface.html">Preface</a></li>
<li class="toctree-l1"><a class="reference internal" href="00_how_to_read.html">如何读这本书</a></li>
<li class="toctree-l1"><a class="reference internal" href="Part1.html">Part 1 一种新的数字格式Unum</a></li>
<li class="toctree-l1"><a class="reference internal" href="01_Overview.html">1 概论</a></li>
<li class="toctree-l1"><a class="reference internal" href="02_BuildUpUnumFormat.html">2. 构造unum的格式</a></li>
<li class="toctree-l1"><a class="reference internal" href="03_TheOriginalSin.html">3. 计算机算术的原罪</a></li>
<li class="toctree-l1"><a class="reference internal" href="04_unum_format.html">4. 完整的unum格式定义</a></li>
<li class="toctree-l1"><a class="reference internal" href="05_hidden_scratchpads_3_layers.html">5. 隐藏的草稿本和三个层次</a></li>
<li class="toctree-l1"><a class="reference internal" href="06_info_per_bit.html">6 每个比特的信息</a></li>
<li class="toctree-l1"><a class="reference internal" href="07_fixed_size_unum_storage.html">7 定长的unum存储</a></li>
<li class="toctree-l1"><a class="reference internal" href="08_comparison_operations.html">8 比较操作</a></li>
<li class="toctree-l1"><a class="reference internal" href="09_add_sub_unbias_round.html">9 加减法和无偏差舍入的迷</a></li>
<li class="toctree-l1"><a class="reference internal" href="10_mul_div.html">10 乘法和除法</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">11 求幂</a></li>
<li class="toctree-l1"><a class="reference internal" href="12_other_important_unary_ops.html">12 其他重要的一元运算</a></li>
<li class="toctree-l1"><a class="reference internal" href="13_fused_operations.html">13 融合操作(一次性表达式)</a></li>
<li class="toctree-l1"><a class="reference internal" href="14_trial_runs.html">14 试运行:Unums 面临计算挑战</a></li>
<li class="toctree-l1"><a class="reference internal" href="part1_summary.html">小结</a></li>
<li class="toctree-l1"><a class="reference internal" href="Part2.html">Part 2 - 一种新的解决方法 Ubox</a></li>
<li class="toctree-l1"><a class="reference internal" href="15_TheOtherKindOfError.html">15. 另外一种误差</a></li>
<li class="toctree-l1"><a class="reference internal" href="16_avoid_interval_arith_pitfalls.html">16 避免区间算术陷阱</a></li>
<li class="toctree-l1"><a class="reference internal" href="17_meaning_of_solve_equ.html">17 “解”方程到底是什么意思?</a></li>
<li class="toctree-l1"><a class="reference internal" href="18_permission_to_guess.html">18 准许猜测</a></li>
<li class="toctree-l1"><a class="reference internal" href="19_pendulums_done_correctly.html">19 摆的正确计算</a></li>
<li class="toctree-l1"><a class="reference internal" href="20_two_body_problem.html">20 二体问题(以及多体问题)</a></li>
<li class="toctree-l1"><a class="reference internal" href="21_calculus_evil.html">21 微积分被认为是邪恶的:离散物理</a></li>
<li class="toctree-l1"><a class="reference internal" href="22_end_of_error.html">22 错误的终结</a></li>
<li class="toctree-l1"><a class="reference internal" href="Glossary.html">词汇表</a></li>
</ul>
</nav>
</div>
</header>
<main class="mdl-layout__content" tabIndex="0">
<script type="text/javascript" src="_static/sphinx_materialdesign_theme.js "></script>
<header class="mdl-layout__drawer">
<!-- Title -->
<span class="mdl-layout-title">
<a class="title" href="index.html">
<span class="title-text">
THE END of ERROR - Unum Computing
</span>
</a>
</span>
<div class="globaltoc">
<span class="mdl-layout-title toc">Table Of Contents</span>
<nav class="mdl-navigation">
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="Preface.html">Preface</a></li>
<li class="toctree-l1"><a class="reference internal" href="00_how_to_read.html">如何读这本书</a></li>
<li class="toctree-l1"><a class="reference internal" href="Part1.html">Part 1 一种新的数字格式Unum</a></li>
<li class="toctree-l1"><a class="reference internal" href="01_Overview.html">1 概论</a></li>
<li class="toctree-l1"><a class="reference internal" href="02_BuildUpUnumFormat.html">2. 构造unum的格式</a></li>
<li class="toctree-l1"><a class="reference internal" href="03_TheOriginalSin.html">3. 计算机算术的原罪</a></li>
<li class="toctree-l1"><a class="reference internal" href="04_unum_format.html">4. 完整的unum格式定义</a></li>
<li class="toctree-l1"><a class="reference internal" href="05_hidden_scratchpads_3_layers.html">5. 隐藏的草稿本和三个层次</a></li>
<li class="toctree-l1"><a class="reference internal" href="06_info_per_bit.html">6 每个比特的信息</a></li>
<li class="toctree-l1"><a class="reference internal" href="07_fixed_size_unum_storage.html">7 定长的unum存储</a></li>
<li class="toctree-l1"><a class="reference internal" href="08_comparison_operations.html">8 比较操作</a></li>
<li class="toctree-l1"><a class="reference internal" href="09_add_sub_unbias_round.html">9 加减法和无偏差舍入的迷</a></li>
<li class="toctree-l1"><a class="reference internal" href="10_mul_div.html">10 乘法和除法</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">11 求幂</a></li>
<li class="toctree-l1"><a class="reference internal" href="12_other_important_unary_ops.html">12 其他重要的一元运算</a></li>
<li class="toctree-l1"><a class="reference internal" href="13_fused_operations.html">13 融合操作(一次性表达式)</a></li>
<li class="toctree-l1"><a class="reference internal" href="14_trial_runs.html">14 试运行:Unums 面临计算挑战</a></li>
<li class="toctree-l1"><a class="reference internal" href="part1_summary.html">小结</a></li>
<li class="toctree-l1"><a class="reference internal" href="Part2.html">Part 2 - 一种新的解决方法 Ubox</a></li>
<li class="toctree-l1"><a class="reference internal" href="15_TheOtherKindOfError.html">15. 另外一种误差</a></li>
<li class="toctree-l1"><a class="reference internal" href="16_avoid_interval_arith_pitfalls.html">16 避免区间算术陷阱</a></li>
<li class="toctree-l1"><a class="reference internal" href="17_meaning_of_solve_equ.html">17 “解”方程到底是什么意思?</a></li>
<li class="toctree-l1"><a class="reference internal" href="18_permission_to_guess.html">18 准许猜测</a></li>
<li class="toctree-l1"><a class="reference internal" href="19_pendulums_done_correctly.html">19 摆的正确计算</a></li>
<li class="toctree-l1"><a class="reference internal" href="20_two_body_problem.html">20 二体问题(以及多体问题)</a></li>
<li class="toctree-l1"><a class="reference internal" href="21_calculus_evil.html">21 微积分被认为是邪恶的:离散物理</a></li>
<li class="toctree-l1"><a class="reference internal" href="22_end_of_error.html">22 错误的终结</a></li>
<li class="toctree-l1"><a class="reference internal" href="Glossary.html">词汇表</a></li>
</ul>
</nav>
</div>
</header>
<div class="document">
<div class="page-content" role="main">
<div class="section" id="id1">
<h1>11 求幂<a class="headerlink" href="#id1" title="Permalink to this heading">¶</a></h1>
<div class="figure align-default" id="id11">
<img alt="_images/image-20230625084059227.png" src="_images/image-20230625084059227.png" />
<p class="caption"><span class="caption-number">Fig. 164 </span><span class="caption-text">image-20230625084059227</span><a class="headerlink" href="#id11" title="Permalink to this image">¶</a></p>
</div>
<blockquote>
<div><p>在10.1节有做一个三维的图来显示乘法<span class="math notranslate nohighlight">\(z=x\times y\)</span>
的鞍形面。求幂函数<span class="math notranslate nohighlight">\(z=x^y\)</span>也是类似的鞍形面,上图用等高线图来显示。红色的角是上升的而蓝色是下降的。计算这个函数意味着要穿越异常情况的雷区,并面临以前未解决的数学难题。</p>
</div></blockquote>
<div class="section" id="id2">
<h2>11.1 平方<a class="headerlink" href="#id2" title="Permalink to this heading">¶</a></h2>
<p>与四种基本算术运算相比,找到 <span class="math notranslate nohighlight">\(x\)</span> 和 <span class="math notranslate nohighlight">\(y\)</span> 的通用幂函数
<span class="math notranslate nohighlight">\(x^y\)</span> 是一个需要巨大努力的跳跃。
我们先从一个非常柔和的抛掷开始本章,创建 <span class="math notranslate nohighlight">\(x^2\)</span>
的例程,因为平方是一种常见的操作。
但是即使这个简单的任务也带来了挑战,我们将在第 2
部分中更详细地讨论这一挑战。为什么不通过将 x 乘以自身来计算 x 的平方呢?</p>
<p>假设<span class="math notranslate nohighlight">\(u\)</span>是表征<span class="math notranslate nohighlight">\([-1, 2)\)</span>的一个unum。这里说明为什么我们不简单第将<span class="math notranslate nohighlight">\(u\otimes u\)</span>来计算<span class="math notranslate nohighlight">\(u\)</span>的平方。平方的结果应该是<span class="math notranslate nohighlight">\([0, 4]\)</span>,
但是不动脑子地用乘法就会丢失两个数是相同的这个信息,结果产生了更宽松的(尽管也是正确的)一个范围<span class="math notranslate nohighlight">\((-2, 4]\)</span>
。</p>
<div class="figure align-default" id="id12">
<img alt="_images/image-20230625091914553.png" src="_images/image-20230625091914553.png" />
<p class="caption"><span class="caption-number">Fig. 165 </span><span class="caption-text">image-20230625091914553</span><a class="headerlink" href="#id12" title="Permalink to this image">¶</a></p>
</div>
<p>对数字进行平方永远不会产生任何负数,但乘法例程会产生的这样的结果结果,因为它错误地假设其输入值是独立的。
因此,平方代码需要注意跨越零的范围。 在精心制作的 unum
环境中,写入“<span class="math notranslate nohighlight">\(x \otimes x\)</span>”应该会触发错误并向用户询问“您的意思是对
x 进行平方吗?”</p>
<p>用乘法还会产生错误的边界,比如$(-2, 2]的平方是[0, 4], 而不是[0, 4).
闭边界点“赢了”开边界点。</p>
<p>原型中,
g-layer函数是<strong>squareg</strong>[g],u-layer版本是<strong>squareu</strong>[u]。代码在附录C.14.
下面是一个<strong>squareg</strong>的范例</p>
<div class="figure align-default" id="id13">
<img alt="_images/image-20230625094700076.png" src="_images/image-20230625094700076.png" />
<p class="caption"><span class="caption-number">Fig. 166 </span><span class="caption-text">image-20230625094700076</span><a class="headerlink" href="#id13" title="Permalink to this image">¶</a></p>
</div>
<p>u-layer中<strong>squareu</strong>[u]的参数u是unum或是ubound,它还统计移动的个数和移动的比特位数;对于一元运算(具有一个输入的运算),移动的个数增加
2(一进一出),移动的比特位数是输入和输出中位的总和。</p>
<div class="figure align-default" id="id14">
<img alt="_images/image-20230625095112426.png" src="_images/image-20230625095112426.png" />
<p class="caption"><span class="caption-number">Fig. 167 </span><span class="caption-text">image-20230625095112426</span><a class="headerlink" href="#id14" title="Permalink to this image">¶</a></p>
</div>
<table border="2"><tr><td bgcolor="lightgray"><p>读者的练习对于区间的立方函数应该用什么样的算法?</p>
</td></tr></table><p>平方函数适用于所有实数和无穷大。 硬件需求并不比乘法更大。 如果我们使用
<span class="math notranslate nohighlight">\(x\)</span> 的更高整数幂,例如 <span class="math notranslate nohighlight">\(x^3\)</span> 、 <span class="math notranslate nohighlight">\(x^4\)</span>
等,我们通常需要扩展精度乘法器,甚至是真正大的乘法器。
在我们讨论之前,考虑另一个非常常见的幂函数:<span class="math notranslate nohighlight">\(x^{1/2}\)</span>,<span class="math notranslate nohighlight">\(x\)</span>
的平方根。</p>
</div>
<div class="section" id="id3">
<h2>11.2 平方根<a class="headerlink" href="#id3" title="Permalink to this heading">¶</a></h2>
<p>不精确的平方根是无理数; 它们不能表示为两个整数 p/q 的比率。
然而,它们并不是超越数,这听起来像是只有数学家才会关心的区别。
平方根是代数数,定义为代数方程(具有有理系数的多项式)的根的数字。
在一个 ULP 内计算代数数很容易,因为有很多快速方法可以找到代数方程的根。
对于平方根,有一些技术可以使每次迭代的正确位数加倍。
在硬件中计算平方根实际上并不比计算数字的倒数更难。
这就是为什么非数学家可能关心代数数和超越数之间的区别:<strong>速度</strong>。</p>
<p>如果用于负数,平方根函数将返回 NaN,因为我们将计算限制为实数。
然而,平方根允许精确的“负零”起作用,而不是将结果声明为虚数,因为如果值恰好为零,则符号位将被忽略。
不过,不精确的负零总是会产生虚数结果,因为它包含严格小于零的数字。
因此,对于这些情况我们必须返回 NaN。 解包的 unum
格式使得检查触发异常的值变得简单快捷。</p>
<p>顺便提一下,IEEE标准规定负零的平方根应该是……<em>负零</em>。
他们到底在想什么啊?? 那是伯克利,而且是 20 世纪 80
年代,所以可能涉及到一些受管制的物质(大麻吗?)。 Unum
数学对于精确浮点数零时是会忽略符号的。</p>
<p>原型中g-layer的平方根函数是<strong>sqrtg</strong>[g],
参数g是<em>通用区间</em>。u-layer的对应函数是<strong>sqrtu</strong>[u],u是ubound。试一下求<span class="math notranslate nohighlight">\((1, \frac{25}{16}]\)</span>
的平方根,开区间端点还是保持开区间,闭区间端点是精确数,其平方根也是精确数,所以也保持闭区间。跟以前一样,端点1做为开端点的方式是设置ubit(也就是加上<strong>ubitmask</strong>到unum位串上)。<span class="math notranslate nohighlight">\((1, \frac{25}{16}]\)</span>
的平方根应该是<span class="math notranslate nohighlight">\((1, \frac{5}{4}]\)</span> :</p>
<div class="figure align-default" id="id15">
<img alt="_images/image-20230625102455563.png" src="_images/image-20230625102455563.png" />
<p class="caption"><span class="caption-number">Fig. 168 </span><span class="caption-text">image-20230625102455563</span><a class="headerlink" href="#id15" title="Permalink to this image">¶</a></p>
</div>
<p><em>通用区间</em>求平方根很容易,因为该函数是单调递增的。
这意味着只需评估每个端点的平方根,如上例所示;
它保留了小于、大于的顺序。 该性质不适用于平方函数,这导致了复杂性。</p>
<p>大多数平方根都是无法用精确浮点数表示的数字,因此就像其他所有运算一样,我们创建一个包含真实值的开区间。
如果端点闭合且平方根准确,则端点保持闭合状态。 否则,ubound
算术会找到包含平方根的最小可能 ULP,并使用 unum 来包含该端点处的正确值。</p>
<p>在下面的示例中,我们显示了底层的 unum
机制,以显示左端点如何精确且紧凑(除了 utag
之外仅有三位),而值为<span class="math notranslate nohighlight">\(\sqrt{3}\)</span>
的端点则需要所有可用的小数位并被标记为不精确。</p>
<div class="figure align-default" id="id16">
<img alt="_images/image-20230625103316847.png" src="_images/image-20230625103316847.png" />
<p class="caption"><span class="caption-number">Fig. 169 </span><span class="caption-text">image-20230625103316847</span><a class="headerlink" href="#id16" title="Permalink to this image">¶</a></p>
</div>
<p>3的平方根是 1.7320508…,因此上限精确到小数点后五位以上。
如果我们对这个结果求平方,我们将得到一个比我们开始时的 [1, 3]
范围稍大的范围。</p>
<div class="figure align-default" id="id17">
<img alt="_images/image-20230625103636363.png" src="_images/image-20230625103636363.png" />
<p class="caption"><span class="caption-number">Fig. 170 </span><span class="caption-text">image-20230625103636363</span><a class="headerlink" href="#id17" title="Permalink to this image">¶</a></p>
</div>
<p>注意高端是开的,正确的区间[1, 3]包含在其中。</p>
<table border="2"><tr><td bgcolor="lightgray"><p>读者的练习unum
{2,2}环境所有的非负的准确值都列在4.10一节,有多少是有准确的平方根值的?</p>
</td></tr></table><p>除了异常值之外,ubounds 表示的端点就像浮点数,是<span class="math notranslate nohighlight">\(f \times 2^e\)</span>
形式的数字,其中 f 是区间 <span class="math notranslate nohighlight">\([1, 2)\)</span> 中的小数。
请注意,我们总可以通过让 f 位于区间 <span class="math notranslate nohighlight">\([1, 4)\)</span> 中, 来使 <span class="math notranslate nohighlight">\(e\)</span>
成为偶数。 因此,如果硬件发现指数是偶数,则会计算
<span class="math notranslate nohighlight">\(f \times 2^{e/2}\)</span>; 如果指数为奇数,则计算
<span class="math notranslate nohighlight">\(\sqrt{2 f} 2^{(e-1)/2}\)</span>,因此指数非常容易计算并且始终可表示。
unum 与浮点平方根运算的不同之处仅在于 unum
自动最小化用于表示指数的位数。</p>
</div>
<div class="section" id="ulp">
<h2>11.3 嵌套的平方根和“ULP跨接”<a class="headerlink" href="#ulp" title="Permalink to this heading">¶</a></h2>
<p>这看上去对于讨论<span class="math notranslate nohighlight">\(x^y\)</span>是一个奇怪的方向。后面的原因是我们想讨论<span class="math notranslate nohighlight">\(y=\frac{1}{4}, \frac{1}{8}, \frac{1}{16} \cdots\)</span>
幂次作为对于下一步使得<span class="math notranslate nohighlight">\(x^y\)</span>成为通用的函数。</p>
<p>由于平方根是一个表现良好的运算,我们可以用它来求
<span class="math notranslate nohighlight">\(x^{\frac{1}{4}}=\sqrt{\sqrt{x}}\)</span>
,无论是作为一个精确的数字还是包含它的最小 ULP 吗?
答案是肯定的,如果您留意“ULP 跨接”并在其发生时予以纠正。
当然,第一个平方根可能会产生不精确的 unum。
然后,第二个平方根分别处理每个端点,这些端点的平方根可能是不同的不精确
unum,因为区间答案跨越一个精确值,而不是位于相邻 unum 之间的开区间。
信息损失可能会随着每个平方根而累积。</p>
<p>幸运的是,这个问题很容易解决,因为数字的平方可以在scratchpad中准确完成。
下面是在 {3, 3} 环境中的例子,我们尝试通过两次平方根来找到
<span class="math notranslate nohighlight">\(266^{1/4}\)</span> 的答案</p>
<div class="figure align-default" id="id18">
<img alt="_images/image-20230625223217640.png" src="_images/image-20230625223217640.png" />
<p class="caption"><span class="caption-number">Fig. 171 </span><span class="caption-text">image-20230625223217640</span><a class="headerlink" href="#id18" title="Permalink to this image">¶</a></p>
</div>
<p>结果有两个ULP的宽度,因为第二次求平方根跨越了精确值<span class="math notranslate nohighlight">\(\frac{258}{64}\)</span>。但是<strong>他们中只有一个才是正确的</strong>。所以吧端点和跨越点都提升做4次方来(两次平方)来检查(事实上我们只需要做中间点的,这里列出三个值便于说明)</p>
<div class="figure align-default" id="id19">
<img alt="_images/image-20230625223848393.png" src="_images/image-20230625223848393.png" />
<p class="caption"><span class="caption-number">Fig. 172 </span><span class="caption-text">image-20230625223848393</span><a class="headerlink" href="#id19" title="Permalink to this image">¶</a></p>
</div>
<p>啊哈,可以丢弃低部分的ULP,就是从<span class="math notranslate nohighlight">\(\frac{257}{64}\)</span>到<span class="math notranslate nohighlight">\(\frac{258}{64}\)</span>,
因为他们中间不含有266.
所以unum结果是<span class="math notranslate nohighlight">\((\frac{258}{64}, \frac{259}{64})\)</span></p>
<p>这个技术可以很容易地推广到嵌入的平方根</p>
<div class="figure align-default" id="id20">
<img alt="_images/image-20230625224255546.png" src="_images/image-20230625224255546.png" />
<p class="caption"><span class="caption-number">Fig. 173 </span><span class="caption-text">image-20230625224255546</span><a class="headerlink" href="#id20" title="Permalink to this image">¶</a></p>
</div>
<p>当任何时候发现根跨越了精确值,所以有两个ULP,都可以通过平方返回看哪一部分是正确值,然后继续。所以我们现在求
<span class="math notranslate nohighlight">\(x^y\)</span> 的方法是“只要 y 是 2 的整数次幂”。 对于 2
的正幂,进行嵌套平方。 对于 2 的负幂,进行嵌套平方根,同时修剪“坏 ULP”。
如果指数为负数,只需计算其绝对值,最后取倒数即可。</p>
</div>
<div class="section" id="id4">
<h2>11.4 对暂存器征税:整数的整数幂<a class="headerlink" href="#id4" title="Permalink to this heading">¶</a></h2>
<p>它被称为“高能power”函数是有原因的。
仅仅因为表达式易于记录,并不意味着它易于计算。 阶乘函数
<span class="math notranslate nohighlight">\(n!= 1 \times 2 \times \cdots \times n\)</span> 就是一个很好的例子;
即使对于低至 n = 70 的数字,n! 比googol还大。 googol
也很容易用五个字符写下来:<span class="math notranslate nohighlight">\(10^{100}\)</span>。幂函数与
<span class="math notranslate nohighlight">\(+ – \times \div\)</span> 属于完全不同的类别;
它很容易产生大量的工作才能计算到最高精度。 那需要的暂存器必须有多大呢?</p>
<p>它的位数很多,但并不像乍看起来那么糟糕,因为比例因子(指数)的单独存储意味着我们只处理由分数位表示的整数。
为了将其简化为足够小的数字以便于掌握,假设 unum 环境为 {2,
2},因此最多有 <span class="math notranslate nohighlight">\(2^2 = 4\)</span> 位来保存分数。 使用隐藏位,分数表示 0 到
31 的整数,按 2 的幂缩放。如果我们需要精确表达整数,暂存器需要保存大到
<span class="math notranslate nohighlight">\(31^31\)</span> 的整数。 这可能看起来很可怕,但它最多只需要 155 位。 表示
31 需要 5 位,因此 <span class="math notranslate nohighlight">\(31^2\)</span> 需要 10 位,<span class="math notranslate nohighlight">\(31^3\)</span> 需要 15
位,依此类推,因此 <span class="math notranslate nohighlight">\(31^31\)</span> 最多需要 <span class="math notranslate nohighlight">\(5 \times 31 = 155\)</span> 位</p>
<p>如果我们构建一个具有直接硬件支持的 unum 环境,最高可达 {4, 5}
的环境,则最大小数长度加上隐藏位的长度为 33 位。 分数位表示的整数范围为
0 到 <span class="math notranslate nohighlight">\(2^{33} - 1\)</span>,或 0 到 8 589 934
591。最大的整数幂将需要(最多)这么多位来存储:</p>
<div class="math notranslate nohighlight" id="equation-11-power-0">
<span class="eqno">(37)<a class="headerlink" href="#equation-11-power-0" title="Permalink to this equation">¶</a></span>\[33 \times 8589934591 = 283467841503 \text{ bits }\]</div>
<p>更通常的说法是,大约 33 GB。 在2014
年,这么大的存储空间是介于便携式计算机和服务器的主内存大小之间。</p>
<p>所以这是一个很大的数字,但这样的硬件是存在的。
当前一代微处理器只需不到一秒的时间即可读取或写入这么多外部数据,按照人类标准来说已经足够快了,但比加法或乘法慢十亿倍。
如果我们想要与四种算术运算具有相同的绝对精度标准,那么一般 x 和 y
的幂函数 <span class="math notranslate nohighlight">\(x^y\)</span> 就不是我们应该随意要求的运算。</p>
<p>现在我们知道我们面临的是什么,尝试计算一个小环境的 <span class="math notranslate nohighlight">\(x^y\)</span> 。</p>
</div>
<div class="section" id="xy">
<h2>11.5 低精度 xy 的计算练习<a class="headerlink" href="#xy" title="Permalink to this heading">¶</a></h2>
<p>我们可以在{2,
2}环境中精确表示数据<span class="math notranslate nohighlight">\(x=17\)</span>和<span class="math notranslate nohighlight">\(y=\frac{3}{8}\)</span>.试着计算<span class="math notranslate nohighlight">\(x^y=17^{\frac{3}{8}}\)</span>.
修改表示<span class="math notranslate nohighlight">\(17^{\frac{3}{8}}=(17^3)^{\frac{1}{8}}\)</span>.
在暂存区中几次乘法可以得到17的三次方,然后用12.4节描述的嵌套平方根来做<span class="math notranslate nohighlight">\(\frac{1}{8}\)</span>,.</p>
<p>数字 17 占用 5 位,因此 <span class="math notranslate nohighlight">\(17^3\)</span> = 4913 在暂存器中最多需要 15 位。
这是一个足够小的位数,我们实际上可以查看 4913 的二进制字符串:</p>
<div class="figure align-default" id="id21">
<img alt="_images/image-20230626162320696.png" src="_images/image-20230626162320696.png" />
<p class="caption"><span class="caption-number">Fig. 174 </span><span class="caption-text">image-20230626162320696</span><a class="headerlink" href="#id21" title="Permalink to this image">¶</a></p>
</div>
<p>对于平方根,我们需要指数为偶数。 要求比例因子 <span class="math notranslate nohighlight">\(2^e\)</span> 的 8
次方根,我们需要 e 是 8 的整数倍。因此,将 4913 的位串向右滑动八位:</p>
<p><span class="math notranslate nohighlight">\(1 001 100 110 001 = 10 011.00110001 \times 2^8\)</span></p>
<p>当然<span class="math notranslate nohighlight">\(2^8\)</span>的8次根就是<span class="math notranslate nohighlight">\(2^1\)</span>.
所以我们寻找一个ULP精度的值<span class="math notranslate nohighlight">\((10011.00110001)^{\frac{1}{8}}\times 2^1\)</span>,用unum表示的二进制如下</p>
<div class="figure align-default" id="id22">
<img alt="_images/image-20230626163058644.png" src="_images/image-20230626163058644.png" />
<p class="caption"><span class="caption-number">Fig. 175 </span><span class="caption-text">image-20230626163058644</span><a class="headerlink" href="#id22" title="Permalink to this image">¶</a></p>
</div>
<p>现在执行三个连续的平方根运算,检查每个运算是否存在跨式,并在必要时进行修剪。
(符号“2^^”后跟零和一允许直接输入位字符串。它们使用通常的系统进行颜色编码,以便更容易查看
unum 位字段。)</p>
<div class="figure align-default" id="id23">
<img alt="_images/image-20230626163426586.png" src="_images/image-20230626163426586.png" />
<p class="caption"><span class="caption-number">Fig. 176 </span><span class="caption-text">image-20230626163426586</span><a class="headerlink" href="#id23" title="Permalink to this image">¶</a></p>
</div>
<p>那个落在 ULP 内,所以不需要修剪。
平方根运算将值的相对宽度缩小约一半,因此新范围大约有一半的时间不会跨越两个
ULP。 执行第二次平方根:</p>
<div class="figure align-default" id="id24">
<img alt="_images/image-20230626163803353.png" src="_images/image-20230626163803353.png" />
<p class="caption"><span class="caption-number">Fig. 177 </span><span class="caption-text">image-20230626163803353</span><a class="headerlink" href="#id24" title="Permalink to this image">¶</a></p>
</div>
<p>请注意,指数字段不断缩小。 它再次降落在一个可能最小的 ULP 内;
对于最后的平方根,我们不会那么幸运。</p>
<div class="figure align-default" id="id25">
<img alt="_images/image-20230626163909020.png" src="_images/image-20230626163909020.png" />
<p class="caption"><span class="caption-number">Fig. 178 </span><span class="caption-text">image-20230626163909020</span><a class="headerlink" href="#id25" title="Permalink to this image">¶</a></p>
</div>
<p>由于小数少于四位,因此它跨越了一个精确值。
有两种快速方法可以知道发生了跨式:小数未达到其最大长度,或者答案的
ubound 是 unum 对而不是单个 unum。
这是前者的情况,因为小数字段仅使用其最多四位中的三位。</p>
<p>计算范围 <span class="math notranslate nohighlight">\((1.375, 1.5)\)</span> 横跨以下精确的 unum:</p>
<div class="figure align-default" id="id26">
<img alt="_images/image-20230626164610459.png" src="_images/image-20230626164610459.png" />
<p class="caption"><span class="caption-number">Fig. 179 </span><span class="caption-text">image-20230626164610459</span><a class="headerlink" href="#id26" title="Permalink to this image">¶</a></p>
</div>
<p>通过重复平方求出跨式精确值的 8 次方。 如果它大于原始数字
10011.00110001,那么我们会删除两个 ULP 中较大的一个;
否则我们就修剪较小的那一个。 再次为了说明,以下是所有三个值的 8 次方:</p>
<div class="figure align-default" id="id27">
<img alt="_images/image-20230626164836148.png" src="_images/image-20230626164836148.png" />
<p class="caption"><span class="caption-number">Fig. 180 </span><span class="caption-text">image-20230626164836148</span><a class="headerlink" href="#id27" title="Permalink to this image">¶</a></p>
</div>
<p>范围 {12.77… ,18.23… } 不包含 10 011.00110001 = 19.19140625,因此被剪掉</p>
<table border="2"><tr><td bgcolor="lightgray"><p>读者的练习如果每次使用 k 个嵌套平方根求一个数的 2^k
根时都会发生跨ULP,那么修剪虚假 ULP 范围所需的乘法总数是多少?</p>
</td></tr></table><p>最后,将最终的 ULP 范围的 unum 按指数 <span class="math notranslate nohighlight">\(2^1\)</span> 缩放,以获得
<span class="math notranslate nohighlight">\(17^{3/8}\)</span> 的最大可用精度(使用的小数字段的所有四位):</p>
<div class="figure align-default" id="id28">
<img alt="_images/image-20230626195620678.png" src="_images/image-20230626195620678.png" />
<p class="caption"><span class="caption-number">Fig. 181 </span><span class="caption-text">image-20230626195620678</span><a class="headerlink" href="#id28" title="Permalink to this image">¶</a></p>
</div>
<p>在研究计算幂函数的问题时,作者在有关该主题的文献中发现了这一非同寻常且经常被引用的说法:</p>
<table border="2"><tr><td bgcolor="lightyellow"><p>“没有人知道对于两个不上溢/下溢的浮点参数计算 y^w,
并且做正确舍入会花费多少……不存在通用方法来预测需要携带多少额外数字来计算
超越表达式并将其正确舍入为某个预先指定的位数。
即使是有限数量的额外数字最终就足够的事实(如果为真)也可能是一个深刻的定理。—
William Kahan</p>
</td></tr></table><p>真的吗??</p>
<p>对于读到这里的人来说,这句话的第一部分肯定不再正确。
我们刚刚展示了计算两个浮点数的幂函数所需的最大成本和最长时间。
这样做的高昂成本让我们急于寻找更好的方法,但这是可预测的有限成本和时间,绝对保证。
它与位串相乘和相加的方法一样具有确定性。</p>
<p>引文是具有误导性的,可能是由于遗漏。 这段引文的“…
…”部分可能遗漏了一个解释,即<strong>如果 y 和 w 是浮点数,则
:math:`y^w`不是超越函数</strong>,因为这样问题就是代数问题,Kahan知道这一点。
上述引用的第二部分仍然正确,计算超越函数 <span class="math notranslate nohighlight">\(e^x\)</span> 的实用方法将在 11.7
节中讨论。</p>
</div>
<div class="section" id="id5">
<h2>11.6 实际考虑和实际工作流程<a class="headerlink" href="#id5" title="Permalink to this heading">¶</a></h2>
<div class="section" id="id6">
<h3>11.6.1 为什么幂函数可以计算得很快<a class="headerlink" href="#id6" title="Permalink to this heading">¶</a></h3>
<p>说到这里,可能有读者会想:这家伙是不是疯了??
精确计算数亿位数字,只是为了保证 <span class="math notranslate nohighlight">\(x^y\)</span> 的正确性?
这不是这里所提议的。
关于最大位数和最大计算步骤数的争论是为了证明两者都有一个预先已知的有限上限。
这不是计算 <span class="math notranslate nohighlight">\(x^y\)</span> 的实用方法,而更像是“存在证明”。</p>
<p>在实践中,我们愿意容忍两件事,这可以使寻找 <span class="math notranslate nohighlight">\(x^y\)</span>
的工作变得更加容易:</p>
<ul class="simple">
<li><p>我们不要求例程对于任意两个输入值始终花费相同的执行时间。</p></li>
<li><p>我们并不要求每个结果都具有可证明的最小 ULP 宽度</p></li>
</ul>
<p>几乎每个 unums
操作都涉及不同数量的执行时间。找到任何精度乘法的最大时间,并坚持处理器始终用那么多时钟周期,即使在将有限数乘以零时也是如此,是很荒唐的做法。
每个操作都应该尽可能快地进行。</p>
<p>至于要求“可证明的最小 ULP 宽度”,有一些计算 <span class="math notranslate nohighlight">\(x^y\)</span>
的有效方法似乎可以做到这一点,但证明它们总是如此准确是很困难的。
然而,Unum 为此提供了完美的解决方案,因为它们包含准确性信息。
如果存在一种非常罕见的情况,即 <span class="math notranslate nohighlight">\(x^y\)</span> 的计算是两个 ULP
宽而不是一个,则 ubound 会指出来。 不可能被结果误导,因为 unum
格式允许传达答案的严格界限的宽度。</p>
</div>
<div class="section" id="id7">
<h3>11.6.2 幂函数原型<a class="headerlink" href="#id7" title="Permalink to this heading">¶</a></h3>
<p>该原型处理幂函数的方法与乘法方法类似。
本章开头的等值线图显示了对马鞍形曲面进行“左边”和“右边”端点计算的非常相似的需求。
在这种情况下,鞍座中心的平坦点不在原点,而是在 <span class="math notranslate nohighlight">\(x = 1, y = 0\)</span>
处。下面的两个表定义了如何处理 x-y 平面中的一般区间端点,其中
<span class="math notranslate nohighlight">\(x \ge 1,y \ge 0\)</span></p>
<div class="figure align-default" id="id29">
<img alt="_images/image-20230626202723921.png" src="_images/image-20230626202723921.png" />
<p class="caption"><span class="caption-number">Fig. 182 </span><span class="caption-text">image-20230626202723921</span><a class="headerlink" href="#id29" title="Permalink to this image">¶</a></p>
</div>
<div class="figure align-default" id="id30">
<img alt="_images/image-20230626202745304.png" src="_images/image-20230626202745304.png" />
<p class="caption"><span class="caption-number">Fig. 183 </span><span class="caption-text">image-20230626202745304</span><a class="headerlink" href="#id30" title="Permalink to this image">¶</a></p>
</div>
<p>如果 <span class="math notranslate nohighlight">\(0 \le x \lt 1\)</span>,我们将计算
<span class="math notranslate nohighlight">\(1/(1/x)^y\)</span>,颠倒左右端点的角色。 如果 x 或 y
为负数,则结果通常为 <span class="math notranslate nohighlight">\(NaN\)</span>(结果是复数而不是实数),除非 y
是整数。 以下是计算幂函数时可能发生的一些特例情况:</p>
<ul class="simple">
<li><p><span class="math notranslate nohighlight">\(0^{-2}=\infty\)</span>, 看起来它应该是
<span class="math notranslate nohighlight">\(NaN\)</span>,因为我们除以零,但即使是零的负整数幂,结果应该是<span class="math notranslate nohighlight">\((\pm\infty)^2=\infty\)</span></p></li>
<li><p><span class="math notranslate nohighlight">\(1^{(maxreal, \infty)}=1\)</span>, 但是<span class="math notranslate nohighlight">\(1^\infty = NaN\)</span></p></li>
<li><p><span class="math notranslate nohighlight">\((-\infty)^\infty=NaN\)</span> but <span class="math notranslate nohighlight">\((-\infty)^{-\infty}=0\)</span></p></li>
</ul>
<p><strong>读者的练习</strong> :
在g-layer中,<span class="math notranslate nohighlight">\((\frac{1}{2},2]^{[-1,1]}\)</span>的正确值是多少?(本章开头的等高线图可能有助于回答这个问题。)</p>
<p>下例是用函数powg计算<span class="math notranslate nohighlight">\([\frac{81}{256}, \frac{625}{256})^{0.75}\)</span></p>
<div class="figure align-default" id="id31">
<img alt="_images/image-20230626204227176.png" src="_images/image-20230626204227176.png" />
<p class="caption"><span class="caption-number">Fig. 184 </span><span class="caption-text">image-20230626204227176</span><a class="headerlink" href="#id31" title="Permalink to this image">¶</a></p>
</div>
<p>u-layer的幂函数<span class="math notranslate nohighlight">\(u^v\)</span>是
<strong>powu</strong>[u,v],它跟踪移动的位数和数字个数。
<strong>powg</strong>和<strong>powu</strong>的代码在附录C.15中,由于所有这些特殊情况要处理,它可能是原型unum环境中所有操作中最复杂的。</p>
</div>
<div class="section" id="id8">
<h3>11.6.3 对浮点数支持者的一个挑战<a class="headerlink" href="#id8" title="Permalink to this heading">¶</a></h3>
<p>对于那些认为自己有一种巧妙的方法可以使用浮点数在 0.5 ULP 内找到
<span class="math notranslate nohighlight">\(x^y\)</span> 的人来说,这是一个挑战问题:请计算</p>
<div class="math notranslate nohighlight" id="equation-11-power-1">
<span class="eqno">(38)<a class="headerlink" href="#equation-11-power-1" title="Permalink to this equation">¶</a></span>\[5.9604644775390625^{0.875}\]</div>
<p>根据大多数数学库例程的工作方式,IEEE 双精度的结果可能接近于</p>
<div class="math notranslate nohighlight" id="equation-11-power-2">
<span class="eqno">(39)<a class="headerlink" href="#equation-11-power-2" title="Permalink to this equation">¶</a></span>\[4.76837158203125\]</div>
<p>库例程会将结果舍入为 15 位十进制数。 它还会根据 IEEE
规则的要求在处理器中设置“舍入”位,但你猜怎么着? 这样做是不对的!
<strong>结果是精确的</strong>,传统的 <span class="math notranslate nohighlight">\(x^y\)</span> 计算方法无法检测到。</p>
<p>我们只需要一个 {3, 5} 环境即可通过原型获得此结果</p>
<div class="figure align-default" id="id32">
<img alt="_images/image-20230626205128754.png" src="_images/image-20230626205128754.png" />
<p class="caption"><span class="caption-number">Fig. 185 </span><span class="caption-text">image-20230626205128754</span><a class="headerlink" href="#id32" title="Permalink to this image">¶</a></p>
</div>
<p>区间方法经常因其对结果产生过于保守的陈述而受到批评。
在这种情况下,应该批评的是浮点数。
上个世纪有一个笑话,有人问工程师“二乘三等于多少?”
他拿出计算尺摆弄了几秒钟,然后宣布:“大约是… …六点零。” 如果值可以在
u-layer中精确地表达,并且它们的初等函数也可以精确地表达,那么如果精确结果被错误地标记为“近似”,则应将其视为错误。</p>
<p><strong>读者的练习</strong> : 构造另一个与上面的例子类似的例子,其中精确的指数
<span class="math notranslate nohighlight">\(y\)</span> 在小数点右侧至少有三位非零数字,而基数 <span class="math notranslate nohighlight">\(x\)</span>
在精确表达时至少有十位小数,并且 <span class="math notranslate nohighlight">\(x^y\)</span> 也是精确的。</p>
</div>
</div>
<div class="section" id="exp-x">
<h2>11.7 Exp(x) 以及“制表者困境”的解决方案<a class="headerlink" href="#exp-x" title="Permalink to this heading">¶</a></h2>
<div class="section" id="id9">
<h3>11.7.1 四舍五入不诚实造成的另一个困境<a class="headerlink" href="#id9" title="Permalink to this heading">¶</a></h3>
<p>指数函数为 <span class="math notranslate nohighlight">\(e^x\)</span>,也写作
exp(x),其中<span class="math notranslate nohighlight">\(e\)</span>是自然对数的底数, 2.718281828… 。 与
<span class="math notranslate nohighlight">\(x^y\)</span> 不同,其中 <span class="math notranslate nohighlight">\(x\)</span> 和 <span class="math notranslate nohighlight">\(y\)</span>
都是浮点数,指数函数是超越函数,不能计算为具有有理系数的多项式方程的根。
幸运的是,有一些快速的方法可以以任何精度对其进行求值。
该算法对数字扩展产生紧缩边界,直到它最终落在最小尺寸的 ULP 内。
然而,所需的迭代次数可以是任意大,因为它可能恰好是一个非常接近精确值的无理数,迫使求值“进入超时”以打破平局。</p>
<p>这是超越计算的示例,以十进制形式显示了此类行为。
<span class="math notranslate nohighlight">\(e^{\pi\sqrt{163}}\)</span>看起来非常像一个整数.
如果对它求值到30个十进制数字精度,结果是</p>
<div class="math notranslate nohighlight" id="equation-11-power-3">
<span class="eqno">(40)<a class="headerlink" href="#equation-11-power-3" title="Permalink to this equation">¶</a></span>\[e^{\pi\sqrt{163}}= 262537412640768743.999999999999 \dots\]</div>
<p>如果最后一位的不确定性甚至小到
<span class="math notranslate nohighlight">\(10^{-12}\)</span>,则此时不知道得出结果的正确 ULP
是略高于整数还是略低于整数。
对数表的早期制作者首先注意到,对几个条目的舍入是非常难以确定的.</p>
<p>卡汉教授为这种现象创造了“制表者的困境”一词。
它源于向表的用户保证的愿望,“我向您保证,此表中的错误条目的偏差不会超过
ULP 的一半。”
制表者困境是浮点数用户被要求犯下的计算机算术“原罪”的直接后果(见第 3.1
节)。</p>
<p><strong>Unums 彻底解决了制表者的困境</strong>。 Unum
不担心所谓“正确舍入”结果,因为它们不做舍入。 如果某个值对于最小可能的
ULP 大小来说是未知的,则只需返回保证能保存该值的更大 ULP 大小(或
ubound); unums
标记边界的大小,而不是返回错误值,unum承认他们不知道的东西。</p>
<p>也就是说,肯定有一种简单的方法可以使像 <span class="math notranslate nohighlight">\(e^x\)</span>
这样的函数的每个值都落在尽可能小的 ULP 大小中。
要么容忍可变长度计算带有偶尔出现(非常罕见)很长的求值时间,就像托马斯·林奇的高基数在线算术那样,要么简单地提前确定哪些浮点数容易出现问题并用表格处理它们。</p>
<p>假设暂存器里面计算一个超越函数,其位数是小数位数的两倍;
从统计上看,在该精度下,恰好跨越 u-layer中两个 ULP 的情况数量大约为 1 。
这就像跟踪硬盘驱动器上的“坏点”。
找出它们在哪里并解决它们,将一个小表作为库函数的一部分,其中预先计算了一些困难的平局情况,因此不必在运行时决定它们</p>
</div>
<div class="section" id="id10">
<h3>11.7.2 指数函数原型<a class="headerlink" href="#id10" title="Permalink to this heading">¶</a></h3>
<p>g-layer版本 <strong>expg</strong> 和 u-layer 版本 <strong>expu</strong> 的代码清单在附录 C.15 中。
因为它是一个单调递增函数,所以所有 ubound
逻辑所要做的就是评估每个边界端点处的函数并跟踪开闭属性。 下面是评估
<span class="math notranslate nohighlight">\(e^{(-\infty, 0]}\)</span> 的示例:</p>
<div class="figure align-default" id="id33">
<img alt="_images/image-20230626212835527.png" src="_images/image-20230626212835527.png" />
<p class="caption"><span class="caption-number">Fig. 186 </span><span class="caption-text">image-20230626212835527</span><a class="headerlink" href="#id33" title="Permalink to this image">¶</a></p>
</div>
<p>有时,人们会养成使用 <span class="math notranslate nohighlight">\(e^x\)</span>
的习惯,而在某些情况下,他们可以使用一个完全可表示的数字作为底数,例如
<span class="math notranslate nohighlight">\(10^x\)</span> 或 <span class="math notranslate nohighlight">\(2^x\)</span>。 原型中有提供
<strong>powu</strong><span class="math notranslate nohighlight">\([\hat{10}, u]\)</span>, 或 <strong>powu</strong>[<span class="math notranslate nohighlight">\(\hat{2}, u\)</span>]
函数,在原型中使用这些函数的好处是:他们有更多得到精确确的情况。
而超越数<span class="math notranslate nohighlight">\(e\)</span>为基数,只有当 <span class="math notranslate nohighlight">\(x\)</span> 为 <span class="math notranslate nohighlight">\(-\infty\)</span>、0 或
<span class="math notranslate nohighlight">\(\infty\)</span> 时,<span class="math notranslate nohighlight">\(e^x\)</span> 才精确的。</p>
<p><strong>读者的练习</strong> : 如果我们在 {2, 2} 环境中限制 utag 左侧最多 5 位,则有
66 个非负可能的 unum 值:</p>
<div class="figure align-default" id="id34">
<img alt="_images/image-20230626213745033.png" src="_images/image-20230626213745033.png" />
<p class="caption"><span class="caption-number">Fig. 187 </span><span class="caption-text">image-20230626213745033</span><a class="headerlink" href="#id34" title="Permalink to this image">¶</a></p>
</div>
<p>如果我们包括这些数的负值,那么就会产生 131 个不同的精确 unum。
在上面的集合中,对于哪一个 <span class="math notranslate nohighlight">\(2^x\)</span> 也是精确的?
(提示:超过百分之十的值都会发生这种情况!)</p>
</div>
</div>
</div>
</div>
<div class="side-doc-outline">
<div class="side-doc-outline--content">
<div class="localtoc">
<p class="caption">
<span class="caption-text">Table Of Contents</span>
</p>
<ul>
<li><a class="reference internal" href="#">11 求幂</a><ul>
<li><a class="reference internal" href="#id2">11.1 平方</a></li>
<li><a class="reference internal" href="#id3">11.2 平方根</a></li>
<li><a class="reference internal" href="#ulp">11.3 嵌套的平方根和“ULP跨接”</a></li>
<li><a class="reference internal" href="#id4">11.4 对暂存器征税:整数的整数幂</a></li>
<li><a class="reference internal" href="#xy">11.5 低精度 xy 的计算练习</a></li>
<li><a class="reference internal" href="#id5">11.6 实际考虑和实际工作流程</a><ul>
<li><a class="reference internal" href="#id6">11.6.1 为什么幂函数可以计算得很快</a></li>
<li><a class="reference internal" href="#id7">11.6.2 幂函数原型</a></li>
<li><a class="reference internal" href="#id8">11.6.3 对浮点数支持者的一个挑战</a></li>
</ul>
</li>
<li><a class="reference internal" href="#exp-x">11.7 Exp(x) 以及“制表者困境”的解决方案</a><ul>
<li><a class="reference internal" href="#id9">11.7.1 四舍五入不诚实造成的另一个困境</a></li>
<li><a class="reference internal" href="#id10">11.7.2 指数函数原型</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="clearer"></div>
</div><div class="pagenation">
<a id="button-prev" href="10_mul_div.html" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--colored" role="botton" accesskey="P">
<i class="pagenation-arrow-L fas fa-arrow-left fa-lg"></i>
<div class="pagenation-text">
<span class="pagenation-direction">Previous</span>
<div>10 乘法和除法</div>
</div>
</a>
<a id="button-next" href="12_other_important_unary_ops.html" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--colored" role="botton" accesskey="N">
<i class="pagenation-arrow-R fas fa-arrow-right fa-lg"></i>
<div class="pagenation-text">
<span class="pagenation-direction">Next</span>
<div>12 其他重要的一元运算</div>
</div>
</a>
</div>
</main>
</div>
</body>
</html>