mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-11-02 11:01:36 +00:00
rebuild
This commit is contained in:
211
ch3/ch3-02.html
211
ch3/ch3-02.html
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="3.2" data-chapter-title="浮點數" data-filepath="ch3/ch3-02.md" data-basepath=".." data-revision="Wed Dec 16 2015 10:54:29 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="3.2" data-chapter-title="浮點數" data-filepath="ch3/ch3-02.md" data-basepath=".." data-revision="Mon Dec 21 2015 12:51:02 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<b>0.5.</b>
|
||||
|
||||
緻謝
|
||||
致謝
|
||||
</a>
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
<b>1.3.</b>
|
||||
|
||||
査找重復的行
|
||||
査找重複的行
|
||||
</a>
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
|
||||
<b>1.4.</b>
|
||||
|
||||
GIF動畫
|
||||
GIF動畵
|
||||
</a>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
<b>1.6.</b>
|
||||
|
||||
併髮穫取多個URL
|
||||
併發穫取多個URL
|
||||
</a>
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
|
||||
<b>3.3.</b>
|
||||
|
||||
復數
|
||||
複數
|
||||
</a>
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@
|
||||
|
||||
<b>3.4.</b>
|
||||
|
||||
佈爾型
|
||||
布爾型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
|
||||
<b>4.</b>
|
||||
|
||||
復閤數據類型
|
||||
複合數據類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
|
||||
<b>6.2.</b>
|
||||
|
||||
基於指鍼對象的方法
|
||||
基於指針對象的方法
|
||||
</a>
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
|
||||
<b>6.4.</b>
|
||||
|
||||
方法值和方法錶達式
|
||||
方法值和方法表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -953,7 +953,7 @@
|
||||
|
||||
<b>7.1.</b>
|
||||
|
||||
接口是閤約
|
||||
接口是合約
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1073,7 +1073,7 @@
|
||||
|
||||
<b>7.9.</b>
|
||||
|
||||
示例: 錶達式求值
|
||||
示例: 表達式求值
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1103,7 +1103,7 @@
|
||||
|
||||
<b>7.11.</b>
|
||||
|
||||
基於類型斷言識彆錯誤類型
|
||||
基於類型斷言識别錯誤類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
<b>8.2.</b>
|
||||
|
||||
示例: 併髮的Clock服務
|
||||
示例: 併發的Clock服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1229,7 +1229,7 @@
|
||||
|
||||
<b>8.3.</b>
|
||||
|
||||
示例: 併髮的Echo服務
|
||||
示例: 併發的Echo服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
|
||||
<b>8.6.</b>
|
||||
|
||||
示例: 併髮的Web爬蟲
|
||||
示例: 併發的Web爬蟲
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1289,7 +1289,7 @@
|
||||
|
||||
<b>8.7.</b>
|
||||
|
||||
基於select的多路復用
|
||||
基於select的多路複用
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1304,7 +1304,7 @@
|
||||
|
||||
<b>8.8.</b>
|
||||
|
||||
示例: 併髮的字典遍歷
|
||||
示例: 併發的字典遍歷
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@
|
||||
|
||||
<b>8.9.</b>
|
||||
|
||||
併髮的退齣
|
||||
併發的退齣
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1354,7 +1354,7 @@
|
||||
|
||||
<b>9.</b>
|
||||
|
||||
基於共享變量的併髮
|
||||
基於共享變量的併發
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1415,7 +1415,7 @@
|
||||
|
||||
<b>9.4.</b>
|
||||
|
||||
內存衕步
|
||||
內存同步
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1460,7 +1460,7 @@
|
||||
|
||||
<b>9.7.</b>
|
||||
|
||||
示例: 併髮的非阻塞緩存
|
||||
示例: 併發的非阻塞緩存
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1475,7 +1475,7 @@
|
||||
|
||||
<b>9.8.</b>
|
||||
|
||||
Goroutines和綫程
|
||||
Goroutines和線程
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1748,7 +1748,7 @@
|
||||
|
||||
<b>12.1.</b>
|
||||
|
||||
為何需要反射?
|
||||
爲何需要反射?
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1793,7 +1793,7 @@
|
||||
|
||||
<b>12.4.</b>
|
||||
|
||||
示例: 編碼S錶達式
|
||||
示例: 編碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1823,7 +1823,7 @@
|
||||
|
||||
<b>12.6.</b>
|
||||
|
||||
示例: 解碼S錶達式
|
||||
示例: 解碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1975,50 +1975,14 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="14" data-path="exercise/ex.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.</b>
|
||||
|
||||
習題解答
|
||||
</a>
|
||||
|
||||
|
||||
<ul class="articles">
|
||||
|
||||
|
||||
<li class="chapter " data-level="14.1" data-path="exercise/ex-ch1.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex-ch1.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.1.</b>
|
||||
|
||||
第一章 入門
|
||||
</a>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="15" data-path="errata.html">
|
||||
<li class="chapter " data-level="14" data-path="errata.html">
|
||||
|
||||
|
||||
<a href="../errata.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>15.</b>
|
||||
<b>14.</b>
|
||||
|
||||
勘誤
|
||||
</a>
|
||||
@@ -2060,7 +2024,122 @@
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="32-浮點數">3.2. 浮點數</h2>
|
||||
<p>TODO</p>
|
||||
<p>Go語言提供了兩種精度的浮點數, float32 和 float64. 它們的算術規范由 IEEE754 國際標準定義, 該浮點數規范被所有現代的CPU支持.</p>
|
||||
<p>這些數值類型的范圍可以從很微小到很鉅大. 浮點數的范圍極限值可以在 matn 包找到. 常量 math.MaxFloat32 表示 float32 能表示的最大數值, 大約是 3.4e38, 對應的 math.MaxFloat64 常量大約是 1.8e308. 它們能表示的最小值近似分别是1.4e-45 和 4.9e-324.</p>
|
||||
<p>一個 float32 類型的浮點數可以提供大約6個十進製數的精度, 而 float64 則可以提供約 15個十進製數精度; 通常應該優先使用 float64 類型, 因爲 float32 類型的纍計計算誤差很容易擴散, 併且 float32 能精度表示的正整數併不是很大:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> f <span class="hljs-typename">float32</span> = <span class="hljs-number">16777216</span> <span class="hljs-comment">// 1 << 24</span>
|
||||
fmt.Println(f == f+<span class="hljs-number">1</span>) <span class="hljs-comment">// "true"!</span>
|
||||
</code></pre>
|
||||
<p>浮點數的字面值可以直接寫小數部分, 想這樣:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> e = <span class="hljs-number">2.71828</span> <span class="hljs-comment">// (approximately)</span>
|
||||
</code></pre>
|
||||
<p>小數點前面或後面的數字都可能被省略(例如 .707 或 1.). 很小或很大的數最好用科學計數法書寫, 通過e或E來指定指數部分:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> Avogadro = <span class="hljs-number">6.02214129e23</span>
|
||||
<span class="hljs-keyword">const</span> Planck = <span class="hljs-number">6.62606957e-34</span>
|
||||
</code></pre>
|
||||
<p>用 Printf 函數的 %g 參數打印浮點數, 將采用緊湊的表示形式打印, 併提供足夠的精度, 但是對應表格的數據, 使用 %e (帶指數) 或 %f 的形式打印可能更合適. 所有的這三個打印形式都可以指定打印的寬度和控製打印精度.</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">for</span> x := <span class="hljs-number">0</span>; x < <span class="hljs-number">8</span>; x++ {
|
||||
fmt.Printf(<span class="hljs-string">"x = %d e^x = %8.3f\n"</span>, x, math.Exp(<span class="hljs-typename">float64</span>(x)))
|
||||
}
|
||||
</code></pre>
|
||||
<p>上面代碼打印e的冪, 打印精度是小數點後三個小數精度和8個字符寬度:</p>
|
||||
<pre><code>x = 0 e^x = 1.000
|
||||
x = 1 e^x = 2.718
|
||||
x = 2 e^x = 7.389
|
||||
x = 3 e^x = 20.086
|
||||
x = 4 e^x = 54.598
|
||||
x = 5 e^x = 148.413
|
||||
x = 6 e^x = 403.429
|
||||
x = 7 e^x = 1096.633
|
||||
</code></pre><p>math 包中除了提供大量常用的數學函數外, 還提供了IEEE754標準中特殊數值的創建和測試: 正無窮大和負無窮大, 分别用於表示太大溢齣的數字和除零的結果; 還有 NaN 非數, 一般用於表示無效的除法操作結果 0/0 或 Sqrt(-1).</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> z <span class="hljs-typename">float64</span>
|
||||
fmt.Println(z, -z, <span class="hljs-number">1</span>/z, -<span class="hljs-number">1</span>/z, z/z) <span class="hljs-comment">// "0 -0 +Inf -Inf NaN"</span>
|
||||
</code></pre>
|
||||
<p>函數 math.IsNaN 用於測試一個數是否是非數 NaN, math.NaN 則返迴非數對應的值. 雖然可以用 math.NaN 來表示一個非法的結果, 但是測試一個結果是否是非數 NaN 則是充滿風險, 因爲 NaN 和任何數都是不相等的:</p>
|
||||
<pre><code class="lang-Go">nan := math.NaN()
|
||||
fmt.Println(nan == nan, nan < nan, nan > nan) <span class="hljs-comment">// "false false false"</span>
|
||||
</code></pre>
|
||||
<p>如果一個函數返迴的浮點數結果可能失敗, 最好的做法是用單獨的標誌報告失敗, 像這樣:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">func</span> compute() (value <span class="hljs-typename">float64</span>, ok <span class="hljs-typename">bool</span>) {
|
||||
<span class="hljs-comment">// ...</span>
|
||||
<span class="hljs-keyword">if</span> failed {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>, <span class="hljs-constant">false</span>
|
||||
}
|
||||
<span class="hljs-keyword">return</span> result, <span class="hljs-constant">true</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>接下來的程序演示了浮點計算圖形. 它是帶有兩個參數的 z = f(x, y) 函數的三維形式, 使用了可縮放矢量圖形(SVG)格式輸齣, 一個用於矢量線繪製的XML標準. 圖3.1顯示了 sin(r)/r 函數的輸齣圖形, 其中 r 是 sqrt(x<em>x+y</em>y).</p>
|
||||
<p><img src="../images/ch3-01.png" alt=""></p>
|
||||
<pre><code class="lang-Go">gopl.io/ch3/surface
|
||||
<span class="hljs-comment">// Surface computes an SVG rendering of a 3-D surface function.</span>
|
||||
<span class="hljs-keyword">package</span> main
|
||||
|
||||
<span class="hljs-keyword">import</span> (
|
||||
<span class="hljs-string">"fmt"</span>
|
||||
<span class="hljs-string">"math"</span>
|
||||
)
|
||||
|
||||
<span class="hljs-keyword">const</span> (
|
||||
width, height = <span class="hljs-number">600</span>, <span class="hljs-number">320</span> <span class="hljs-comment">// canvas size in pixels</span>
|
||||
cells = <span class="hljs-number">100</span> <span class="hljs-comment">// number of grid cells</span>
|
||||
xyrange = <span class="hljs-number">30.0</span> <span class="hljs-comment">// axis ranges (-xyrange..+xyrange)</span>
|
||||
xyscale = width / <span class="hljs-number">2</span> / xyrange <span class="hljs-comment">// pixels per x or y unit</span>
|
||||
zscale = height * <span class="hljs-number">0.4</span> <span class="hljs-comment">// pixels per z unit</span>
|
||||
angle = math.Pi / <span class="hljs-number">6</span> <span class="hljs-comment">// angle of x, y axes (=30°)</span>
|
||||
)
|
||||
|
||||
<span class="hljs-keyword">var</span> sin30, cos30 = math.Sin(angle), math.Cos(angle) <span class="hljs-comment">// sin(30°), cos(30°)</span>
|
||||
|
||||
<span class="hljs-keyword">func</span> main() {
|
||||
fmt.Printf(<span class="hljs-string">"<svg xmlns='http://www.w3.org/2000/svg' "</span>+
|
||||
<span class="hljs-string">"style='stroke: grey; fill: white; stroke-width: 0.7' "</span>+
|
||||
<span class="hljs-string">"width='%d' height='%d'>"</span>, width, height)
|
||||
<span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < cells; i++ {
|
||||
<span class="hljs-keyword">for</span> j := <span class="hljs-number">0</span>; j < cells; j++ {
|
||||
ax, ay := corner(i+<span class="hljs-number">1</span>, j)
|
||||
bx, by := corner(i, j)
|
||||
cx, cy := corner(i, j+<span class="hljs-number">1</span>)
|
||||
dx, dy := corner(i+<span class="hljs-number">1</span>, j+<span class="hljs-number">1</span>)
|
||||
fmt.Printf(<span class="hljs-string">"<polygon points='%g,%g %g,%g %g,%g %g,%g'/>\n"</span>,
|
||||
ax, ay, bx, by, cx, cy, dx, dy)
|
||||
}
|
||||
}
|
||||
fmt.Println(<span class="hljs-string">"</svg>"</span>)
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">func</span> corner(i, j <span class="hljs-typename">int</span>) (<span class="hljs-typename">float64</span>, <span class="hljs-typename">float64</span>) {
|
||||
<span class="hljs-comment">// Find point (x,y) at corner of cell (i,j).</span>
|
||||
x := xyrange * (<span class="hljs-typename">float64</span>(i)/cells - <span class="hljs-number">0.5</span>)
|
||||
y := xyrange * (<span class="hljs-typename">float64</span>(j)/cells - <span class="hljs-number">0.5</span>)
|
||||
|
||||
<span class="hljs-comment">// Compute surface height z.</span>
|
||||
z := f(x, y)
|
||||
|
||||
<span class="hljs-comment">// Project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy).</span>
|
||||
sx := width/<span class="hljs-number">2</span> + (x-y)*cos30*xyscale
|
||||
sy := height/<span class="hljs-number">2</span> + (x+y)*sin30*xyscale - z*zscale
|
||||
<span class="hljs-keyword">return</span> sx, sy
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">func</span> f(x, y <span class="hljs-typename">float64</span>) <span class="hljs-typename">float64</span> {
|
||||
r := math.Hypot(x, y) <span class="hljs-comment">// distance from (0,0)</span>
|
||||
<span class="hljs-keyword">return</span> math.Sin(r) / r
|
||||
}
|
||||
</code></pre>
|
||||
<p>要註意的是 corner 返迴了兩個結果, 對應 corner 的坐標參數.</p>
|
||||
<p>要解釋程序是如何工作的需要了解基本的幾何知識, 但是我們可以跳過幾何原理, 因爲程序的重點是演示浮點運算. 程序的本質是三個不同的坐標繫中映射關繫, 如圖3.2所示. 第一個是 100x100 的二維網格, 對應整數整數坐標(i,j), 從遠處的 (0, 0) 位置開始. 我們從遠處像前面繪製, 因此遠處先繪製的多邊形有可能被前面後繪製的多邊形覆蓋.</p>
|
||||
<p>第二個坐標繫是一個三維的網格浮點坐標(x,y,z), 其中x和y是i和j的線性函數, 通過平移轉換位center的中心, 然後用xyrange繫數縮放. 高度z是函數f(x,y)的值.</p>
|
||||
<p>第三個坐標繫是一個二維的畵布, 起點(0,0)在左上角. 畵布中點的坐標用(sx, sy)表示. 我們使用等角投影將三維點</p>
|
||||
<p><img src="../images/ch3-02.png" alt=""></p>
|
||||
<p>(x,y,z) 投影到二維的畵布中. 畵布中從遠處到右邊的點對應較大的x值和較大的y值. 併且畵布中x和y值越大, 則對應的z值越小. x和y的垂直和水平縮放繫數來自30度角的正絃和餘絃值. z的縮放繫數0.4, 是一個任意選擇的參數.</p>
|
||||
<p>對於二維網格中的每一個單位, main函數計算單元的四個頂點在畵布中對應多邊形ABCD的頂點, 其中B對應(i,j)頂點位置, A, C, 和 D是相鄰的頂點, 然後輸齣SVG的繪製指令.</p>
|
||||
<p><strong>練習3.1:</strong> 如果 f 函數返迴的是無限製的 float64 值, 那麽SVG文件可能輸齣無效的<polygon></polygon>多邊形元素(雖然許多SVG渲染器會妥善處理這類問題). 脩改程序跳過無效的多邊形.</p>
|
||||
<p><strong>練習3.2:</strong> 試驗math包中其他函數的渲染圖形. 你是否能輸齣一個egg box, moguls, 或 a saddle 圖案?</p>
|
||||
<p><strong>練習3.3:</strong>根據高度給每個多邊形上色, 那樣峯值部將是紅色(#ff0000), 谷部將是藍色(#0000ff).</p>
|
||||
<p><strong>3.4:</strong> 參考1.7節Lissajous例子的函數, 構造一個web服務器, 用於計算函數麴面然後返迴SVG數據給客戶端. 服務器必鬚設置 Content-Type 頭部:</p>
|
||||
<pre><code class="lang-Go">w.Header().Set(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"image/svg+xml"</span>)
|
||||
</code></pre>
|
||||
<p>(這一步在Lissajous例子中不是必鬚的, 因爲服務器使用標準的PNG圖像格式, 可以根據前面的512個字節自動輸齣對應的頭部.) 允許客戶端通過HTTP請求參數設置高度, 寬度, 和顔色等參數.</p>
|
||||
|
||||
|
||||
</section>
|
||||
@@ -2074,7 +2153,7 @@
|
||||
<a href="../ch3/ch3-01.html" class="navigation navigation-prev " aria-label="Previous page: 整型"><i class="fa fa-angle-left"></i></a>
|
||||
|
||||
|
||||
<a href="../ch3/ch3-03.html" class="navigation navigation-next " aria-label="Next page: 復數"><i class="fa fa-angle-right"></i></a>
|
||||
<a href="../ch3/ch3-03.html" class="navigation navigation-next " aria-label="Next page: 複數"><i class="fa fa-angle-right"></i></a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user