Daniel-0224
A common choice for fixed-point arithmetic in Linux kernel development is a scaling factor of 1024 (corresponds to a shift of 10 bits), which means that
there will be 22 bits for the integer part and 10 bits for the fractional part.
This setup provides a resolution of 2^-10 = 0.00097656, which sufficiently meets the precision requirements of many kernel-related tasks without the need for
extremely fine scales
可以標示一下此段文章的出處。
已修正,感謝指正。
chloe0919
透過右移操作縮減val,右移的位數是local_n 除以LOAD_AVG_PERIOD 的結果。
可否說明為何右移的位數是 local_n 除以LOAD_AVG_PERIOD 的結果
已修正,感謝指正
fennecJ
repo 中提供的測試 程式碼 以及本筆記中摘錄的程式碼含有中文註解,請改為使用美式英語撰寫。
可否在你的筆記中針對 kahan summation, pairwise summation 的計算方法進行簡介,並嘗試分析這兩種計算法有何特性以及各自適合的運算場景?
你的執行程式 runtimetest_fixed_point 在 user space 下進行計時,可能導致結果受到 interrupt/preemption 影響而有所誤差。可以透過撰寫 kernel module 關閉 interrupt/preemption 取得更精準的結果。
已修正,感謝指正及指教
popo8712
在處理浮點數乘 10 的實作中,您提到嘗試 Kahan summation 和 pairwise summation 來消除誤差,但未能成功。能否詳細解釋為什麼這些方法沒有達到預期效果?是否考慮過其他消除浮點數運算誤差的方法?
根據本人對浮點數的了解,這是因為單精度浮點數的格式限制了有效位數,超過小數點後六位仍然無法避免誤差,要同時滿足如此精度以及維持可表示的數值範圍應該是無解;但若是數值不大,或許可以使用定點數,以小數點後六位的精度來說,需要平移至少 20 bits。
mesohandsome
筆記中的圖片全都無法看到,需要修改權限。
圖片權限應該無法修改,可能請您重整看看。
dockyu
我們可以把* 10變成* 8 * 1.25,也就是,在程式碼操作上使用加﹑除﹑位元操作來完成,程式碼如下
0.25 應該是 ,應該改為
已修正,感謝指正
marsh-fish
建議註解用英文書寫。
感謝提醒
lintin528
在你的 normal -> overflow
或其他的情況中,可以嘗試自己設計一些補償機制並訂定資料集來觀察。
了解,感謝指教
david965154
- 直接乘10:
- bitwise 8+2:
- fixed point:
那關於誤差的分析呢,單看這這樣的數據時間似乎差的並不多,可以提供一下在你的測試資料下精度為何
精度部分直接乘與bitwise皆為小數點後六位,定點數部分為小數點後三位。
回顧 IEEE 754,探究其原理並進行案例探討,接著研究 Linux 核心原始程式碼的定點數運算,理解其設計和實作考量。
務必依循 IEEE 754 規格書來探討浮點數標準和關鍵考量
Triples指的是:sign, exponent, significand。
修正圖片的存取權限。
當 e=emin and 0<m<1,則歸類為 Subnormal numbers
對無限操作數的運算通常是精確的,因此不會觸發異常(exception),除了某些例外
例外
使用 LaTeX 符號
NaN有兩種: signaling and quiet
在 IEEE 754 ch3.6 可以看到浮點數的規定如下:
將常用的 binary32, binary64 圖像化表示如下:
數據範圍如下:
修正圖片存取權限
根據 IEEE 754(2008 ver) ch4.3 提到,在計算時一律先計算至無限精度及範圍,再根據條件做四捨五入
Except where stated otherwise, every operation shall be performed as if it first produced an intermediate
result correct to infinite precision and with unbounded range, and then rounded that result according to one
of the attributes in this clause.
由於浮點數並不像實數具有連續性,也不像自然數般均勻分布,而是像電子能階一樣的不均勻分布,因此數值的捨入方式變得需要因地制宜。這邊一共有兩個類型,共五種方案
這邊討論的是尚未碰到最大值的處理方案,一個浮點數的最大值可以表示成:
這邊討論的是用戶可以選擇的捨入方向
注意:
The default rounding-direction attribute for results in decimal formats is language defined, but should be roundTiesToEven.
根據 IEEE754(2008 ver) ch5.1 ,符合本規定的浮點數操作產生的結果大致可分成四類
產生浮點或整數結果,並對所有結果進行四捨五入,有可能觸發浮點異常。
產生浮點結果,且不會觸發浮點異常訊號。本操作又可再分成兩類(5.5)。
不會產生浮點結果,可能會觸發異常;比較操作屬於此類(5.6)。
不會生成浮點結果,也不會觸發異常(5.7)。
此外,根據結果格式和操作數格式之間的關係,操作也可以分成兩類
在 IEEE754(2008ver) ch7.1 提到,異常共有五種。這些事件通常是由於運算超出了正常的數值範圍或邏輯,需要特殊處理。
註: flag 不同於 signal , flag 是一種狀態指示,不會讓程式運行中止。
當沒有有用的可定義結果時,才會發出無效操作異常信號。對於以浮點格式生成結果的操作,發出無效操作異常的預設結果應為 quiet NaN,該 NaN 應提供一些診斷資訊(見 6.2)。這些操作包括:
對於未以浮點格式生成結果的操作,發出無效操作異常信號的操作包括:
當一個運算在有限操作數上執行,並且該運算的結果被定義為無限大時。 這通常涉及到除數為零而被除數為非零的有限數。預設結果如下:
當在沒有指數範圍限制的情況下,經過捨去的浮點運算結果的絕對值超過了目標格式能表示的最大有限數值。以單精度來說,若指數部分的二進位表示法超過 11111111,則觸發 overflow 。捨入方式如第4章所提:
當檢測到微小的非零結果時,應觸發 underflow exception 。對於二進位格式,應在下列兩種方式中選擇一種做為檢測方法:
預設的異常處理方式如下:
除非另有說明,否則當運算的四捨五入結果不精確時(即,它與指數範圍和精度均無界時計算的結果不同),應發出不精確異常的訊號。四捨五入或溢出的結果應交付到目的地。
不能用 mul
也就是 i/o 都是 normal numbers 的情況。
我們可以把* 10變成* 8 * 1.25,也就是,在程式碼操作上使用加﹑除﹑位元操作來完成,程式碼如下
注意書寫規範:
從浮點數的規範可以推知,單精度浮點數的有效位數約為七位,因此測試值的輸出大機率會出現誤差。輸出結果如下。
測試少一位是否有誤(正確):
很明顯的可以看到誤差出現,透過 IEEE-754 Floating Point Converter可以看到實際被存入的數值與輸入不同。
修改圖片的存取權限
再利用另一個 converter得到的結果顯示,該輸入為 inexact ,因此我開始嘗試消除誤差。
(signaling NaN)
bit shift 無解,就是 overflow
Q: 有沒有辦法以同樣位元數來表示結果
A: 可以,但尾數的間距會變大導致誤差,需要額外補償機制
改進你的漢語表達。
bit shift 無解,繼續 overflow
應該有解,會出現quiet nan
或許可以bit shift 到 normal,之後再想要怎麼還原(多乘的倍數如何校正)
參照《Demystifying the Linux CPU Scheduler》關於定點數運算的描述,以 loadavg 和 PELT 等 Linux 核心原始程式碼裡頭的實作,探究其如何處理定點數的除法。
分析能否善用上述利用 bitwise 運算達到「乘 10」的操作」達到簡化運算成本。
將數值縮放後儲存,根據定義的小數點位置決定縮放的比例
在老師所著的 Demystifying the Linux CPU Scheduler 之第69頁提到,小數部分通常放大 倍,原因是符合 Linux 所需的精度(約為小數點後三位)。整數的部份用 22 bits 儲存,小數為 10 bits。
A common choice for fixed-point arithmetic in Linux kernel development is a scaling factor of 1024 (corresponds to a shift of 10 bits), which means that
there will be 22 bits for the integer part and 10 bits for the fractional part.
This setup provides a resolution of 2^-10 = 0.00097656, which sufficiently meets the precision requirements of many kernel-related tasks without the need for
extremely fine scales
範例如圖: 圖中儲存的數值為 123.25,其二進位為1111011.01,位移10 bits 後存進去
為改善進程的CPU時間公平性以及提升效率而被提出的方法,首次出現於 Linux3.8 中。
本法按照每個調度實體(可以是單一進程或整個控制組)來追蹤負載,其中每個實體的負載是基於它們的可運行時間來計算,包括實際運作的時間和等待運作的時間。系統將這些時間劃分為1024 微秒的周期,追蹤每個週期中實體的狀態變化。
實體的負載貢獻:在每個週期中,如果實體是可運作的(無論它是否真正佔用了CPU),都被視為對系統負載有貢獻。 這種方式不僅考慮了實體實際佔用 CPU 的時間,還包括了它在就緒佇列中等待的時間。
負載衰減演算法:為確保負載追蹤的資料不會因時間推移而變得不相關,核心引入了衰減因子(y),用於減少歷史負載資料的影響。 具體來說,32 毫秒前的負載貢獻權重為目前的一半,越早的負載貢獻對目前的調度決策影響越小,這個概念類似一階馬可夫鏈。
透過右移操作縮減val,右移的位數是local_n 除以LOAD_AVG_PERIOD 的結果。
衡量系統負載情況的一個重要指標,它表示系統在特定時間間隔內的平均活躍進程數。 活躍進程指的是那些處於運作狀態或等待狀態(即正在使用或等待使用CPU 資源)的進程。
以除法為例,這邊是透過bit shift來完成的,這部分的程式碼如下:
以下皆為測試 10000 次的運行時間,可以看到定點數運算比直接乘來的快20%左右,但精度只能到小數點後三位。 bitwise可能是我程式碼不夠簡潔才導致運算時間大幅提升。
詳述實驗方法和解讀。