<b>3.2 浮點數</b>
<b></b>
go具有兩種大小的浮點數float32和float64。其算術特性遵從ieee 754标準,所有新式cpu都支援該标準。
這兩個類型的值可從極細微到超宏大。math包給出了浮點值的極限。常量math.maxfloat32是float32的最大值,大約為3.4e38,而math.maxfloat64則大約為1.8e308。相應地,最小的正浮點值大約為1.4e-45和4.9e-324。
十進制下,float32的有效數字大約是6位,float64的有效數字大約是15位。絕大多數情況下,應優先選用float64,因為除非格外小心,否則float32的運算會迅速累積誤差。另外,float32能精确表示的正整數範圍有限:
在源碼中,浮點數可寫成小數,如:
小數點前的數字可以省略(.707),後面的也可省去(1.)。非常小或非常大的數字最好使用科學記數法表示,此方法在數量級指數前寫字母e或e:
浮點值能友善地通過printf的謂詞%g輸出,該謂詞會自動保持足夠的精度,并選擇最簡潔的表示方式,但是對于資料表,%e(有指數)或%f(無指數)的形式可能更合适。這三個謂詞都能掌控輸出寬度和數值精度。
上面的代碼按8個字元的寬度輸出自然對數e的各個幂方,結果保留三位小數:
除了大量常見的數學函數之外,math包還有函數用于建立和判斷ieee 754标準定義的特殊值:正無窮大和負無窮大,它表示超出最大許可值的數及除以零的商;以及nan(not a number),它表示數學上無意義的運算結果(如0/0或sqrt(-1))。
math.isnan函數判斷其參數是否是非數值,math.nan函數則傳回非數值(nan)。在數字運算中,我們傾向于将nan當作信号值(sentinel value),但直接判斷具體的計算結果是否為nan可能導緻潛在錯誤,因為與nan的比較總不成立(除了!=,它總是與==相反):
一個函數的傳回值是浮點型且它有可能出錯,那麼最好單獨報錯,如下:
下一個程式以浮點繪圖運算為例。它根據傳入兩個參數的函數z=f(x,y),繪出三維的網線狀曲面,繪制過程中運用了可縮放矢量圖形(scalable vector graphics,svg),繪制線條的一種标準xml格式。圖3-1是函數sin(r)/r的圖形輸出樣例,其中r為sqrt(x*x+y*y)。
圖3-1 函數sin(r)/r的圖形輸出樣例
注意,corner函數傳回兩個值,構成網格單元其中一角的坐标。
了解這段程式隻需基本的幾何知識,但略過也無妨,因為本例旨在說明浮點運算。這段程式本質上是三套不同坐标系的互相映射,見圖3-2。首先是個包含100×100個單元的二維網格,每個網格單元用整數坐标(i, j)标記,從最遠處靠後的角落(0, 0)開始。我們從後向前繪制,因而後方的多邊形可能被前方的遮住。
圖3-2 三套不同坐标系
第二個坐标系内,網格由三維浮點數(x, y, z)決定,其中x和y由i和j的線性函數決定,經過坐标轉換,原點處于中央,并且坐标系按照xyrange進行縮放。高度值z由曲面函數f(x, y)決定。
第三個坐标系是二維成像繪圖平面(image canvas),原點在左上角。這個平面中點的坐标記作(sx, sy)。我們用等角投影(isometric projection)将三維坐标點(x, y, z)映射到二維繪圖平面上。若一個點的x值越大,y值越小,則其在繪圖平面上看起來就越接近右方。而若一個點的x值或y值越大,且z值越小,則其在繪圖平面上看起來就越接近下方。縱向(x)與橫向(y)的縮放系數是由30°角的正弦值和餘弦值推導而得。z方向的縮放系數為0.4,是個随意標明的參數值。
二維網格中的單元由main函數處理,它算出多邊形abcd在繪圖平面上四個頂點的坐标,其中b對應(i, j),a、c、d則為其他三個頂點,然後再輸出一條svg指令将其繪出。
練習3.1:假如函數f傳回一個float64型的無窮大值,就會導緻svg檔案含有無效的<polygon>元素(盡管很多svg繪圖程式對此處理得當)。修改本程式以避免無效多邊形。
練習3.2:用math包的其他函數試驗可視化效果。你能否生成各種曲面,分别呈雞蛋盒狀、雪坡狀或馬鞍狀?
練習3.3:按高度給每個多邊形上色,使得峰頂呈紅色(#ff0000),谷底呈藍色(#0000ff)。
練習3.4:仿照1.7節的示例lissajous的方法,建構一個web伺服器,計算并生成曲面,同時将svg資料寫入用戶端。伺服器必須如下設定content-type報頭。
(在lissajous示例中,這一步并不強制要求,因為該伺服器使用标準的啟發式規則,根據響應内容最前面的512位元組來識别常見的格式(如png),并生成正确的http報頭。)允許用戶端通過http請求參數的形式指定各種值,如高度、寬度和顔色。