# risc-v 浮點運算-入門篇 ## IEEE-754 ### 簡介 二進位浮點數算術標準,分成四種格式,分別為單精確度(32bits)、雙精確度(64bits)、延伸單精確度(43bits以上,很少使用)與延伸雙精確度(79bits以上,通常以80位元實做) 這個標準是一個業界通用的標準,避免出現各家電腦公司的各個型號的電腦,有著千差萬別的浮點數表示。 ### 格式 IEEE754的浮點指令可以大致上看成下列的結構 ![image](https://hackmd.io/_uploads/BykCxExzJl.png) 由以下三種部份構成:sign、exponent、fraction #### Sign 符號位元 決定數的正負(0 表示正,1 表示負)。 #### Exponent 指數位元 存儲浮點數的指數,使用偏移編碼(Bias Encoding)表示,偏移量為 2^(n-1)-1,其中 n 是指數位的位數。 :::info 指數偏移值(exponent bias),即浮點數表示法中指數域的編碼值,等於指數的實際值加上某個固定的值,IEEE 754標準規定該固定值為2^(n-1)-1,其中n的為儲存指數的位元的長度。 以單精度浮點數為例,它的指數域是8個位元,固定偏移值是2的(8-1)次方 再減1 = 127。此為有號數的表示方式,單精度浮點數的指數部分實際取值是從-126到127(-127和128被用作特殊值處理,見下方「非正規形式的浮點數」和「特殊值」)。例如指數實際值為17(十進制),在單精度浮點數中的指數域編碼值為 144(十) = 17(十) + 127(十) 採用指數的實際值加上固定的偏移值的辦法表示浮點數的指數,好處是可以用長度為 e個位元的無符號整數來表示所有的指數取值,更容易做兩個浮點數的指數大小的比較。 ::: #### Fraction 小數位元 小數部分。默認隱含一個整數 1,因此精度為1.fraction 的形式 #### 默認半/單/雙精度格式 * 半精度(16 位元): 符號位(Sign):1 位 指數位(Exponent):5 位 尾數位(Mantissa/Fraction):10 位 * 單精度(32 位元): 符號位(Sign):1 位 指數位(Exponent):8 位 尾數位(Mantissa/Fraction):23 位 * 雙精度(64 位元): 符號位(Sign):1 位 指數位(Exponent):11 位 尾數位(Mantissa/Fraction):52 位 #### 實例 十進制數字 -27.15625 在IEEE754 half-precision中如何表示? ![image](https://hackmd.io/_uploads/B1ae6Egzyg.png) #強制轉換 ### 特殊值 1. 如果指數是0並且尾數的小數部分是0,這個數±0(和符號位相關) 2. 如果指數 = 2^e-1並且尾數的**小數部分是0**,這個數是±∞(同樣和符號位相關) 3. 如果指數 = 2^e-1並且尾數的**小數部分非0**,這個數表示為非數(NaN)。 ## RISC-V F Standard Extension F standard extension為單精度浮點數(single-precision floating-point)指令擴充,增加了 32個浮點數暫存器(f0-f31),長度為 32-bit,以及一個浮點數控制與狀態暫存器(fcsr)。 ### Floating-Point Control and Status Register ![image](https://hackmd.io/_uploads/B1wt8ref1l.png) FCSR 寄存器分為三個主要部分: 1. FRM, Floating-Point Rounding Mode:第 7 到 5 位(3 bits) 2. FFLAGS, Floating-Point Flags:異常標記字段,第 4 到 0 位(5 bits) 3. Unused Bits:預留字段,第 31 到 8 位,通常未使用 #### FRM - Floating-Point Rounding Mode FRM 用來指定浮點數運算的rounding方式。它是 FCSR 的第 7 到 5 位,占用 3 位,有 5 種rounding模式。這些模式符合 IEEE 754 標準,使浮點數運算結果能夠按照不同的應用需求進行rounding。這些rounding模式如下: :::info #### Rounding 數值計算中小數的取捨方式。在浮點數計算時,結果的精度可能超出硬件能夠表示的範圍,因此需要進行rounding來取得一個近似值 ::: | rounding模式編碼 | 名稱 | 描述 | | -------- | -------- | -------- | | 000 | RNE,Rounding to Nearest, Ties to Even | 將結果rounding到最近的偶數,為 IEEE 754 的默認rounding模式 | | 001 | RTZ,Round towards Zero | 結果直接捨棄小數部分,向零靠攏 | | 010 | RDN,Round Down, towards -∞ | 結果向負無窮大靠攏 | | 011 | RUP,Round Up, towards +∞ | 結果向正無窮大靠攏 | | 100 | RMM,Round to Nearest, Ties to Max Magnitude | 結果向最近值rounding,如遇到tie的情況,則向最大幅度的方向rounding | | 101 | X | 無效(可新增) | | 110 | X | 無效(可新增) | | 111 | X | dynamic rounding | #### FFLAGS - Floating-Point Flags 若發生 floating point exception,則會去設定相對應的 fcsr exception flags,下方表格為各個 flag與其 floating point exception的對照。 | Flag | 名稱 | 描述 | | -------- | -------- | -------- | | 第4位 | NX (Inexact) | 精度損失標記位,當運算結果無法精確表示時設置 | | 第3位 | UF (Underflow) | 下溢標記位,當結果非常接近零且小於最小可表示數時設置 | | 第2位 | OF (Overflow) | 上溢標記位,當結果超出浮點數可表示的最大範圍時設置 | | 第1位 | DZ (Divide by Zero) | 除零標記位,當除數為零時設置 | | 第0位 | NV (Invalid Operation) | 非法操作標記位,當操作數無效或操作結果未定義時設置(如 0/0、NaN 等情況) | ### Single-Precision Load and Store Instructions FLW flw rd, rs1, simm12 常數部分為 sign-extended 12-bit,載入位址則為 rs1一般暫存器加上 sign-extended 12-bit,將 single-precision浮點數值從記憶體中載入 rd浮點數暫存器。 FSW fsw rd, rs1, simm12 常數部分為 sign-extended 12-bit,儲存位址則為 rs1一般暫存器加上 sign-extended 12-bit,將 rs1浮點數暫存器的 single-precision浮點數值寫入記憶體。 ### Single-Presicion Floating-Point Computational Instructions FADD.S/FSUB.S fadd.s/fsub.s rd, rs1, rs2 將 rs1浮點數暫存器與 rs2浮點數暫存器做加法/減法運算,結果寫入 rd浮點數暫存器。 FMUL.S/FDIV.S fmul.s/fdiv.s rd, rs1, rs2 將 rs1浮點數暫存器與 rs2浮點數暫存器做乘法/除法運算,結果寫入 rd浮點數暫存器。 FMIN.S/FMAX.S fmin.s/fmax.s rd, rs1, rs2 將 rs1浮點數暫存器與 rs2浮點數暫存器做最大值/最小值比較,將最大值/最小值寫入 rd浮點數暫存器。 FSQRT.S fsqrt.s rd, rs1 將 rs1浮點數暫存器做取平方根運算,結果寫入 rd浮點數暫存器。 **F[N]MADD/F[N]MSUB** f[n]madd/f[n]msub rd, rs1, rs2, rs3 將 rs1浮點數暫存器與 rs2浮點數暫存器做乘法運算後,再與 rs3浮點數暫存器做加法/乘法運算,結果寫入 rd浮點數暫存器,n版本則為做完乘法運算後取 negate,為乘法與加法指令一次完成,中間並沒有經過 rounding,所以精準度上會比一般乘法指令加上加法指令還高。 ### Single-precision Floating-Point Conversion and Move Instructions 將浮點數與整數之間的轉換指令,會根據指令中的 rm field來決定轉換的 rounding mode。 FCVT.W.S/FCVT.L.S fcvt.w.s/fcvt.l.s rd, rs1 將 rs1浮點數暫存器中的浮點數轉換為 signed 32-bit/64-bit,結果寫入 rd一般暫存器。 FCVT.S.W/FCVT.S.L fcvt.s.w/fcvt.s.l rd, rs1 將 rs1一般暫存器中的signed 整數轉換為浮點數,結果寫入 rd一般暫存器。 FCVT.WU.S/FCVT.LU.S fcvt.wu.s/fcvt.lu.s rd, rs1 將 rs1浮點數暫存器中的浮點數轉換為 unsigned 32-bit/64-bit,結果寫入 rd一般暫存器。 FCVT.S.WU/FCVT.S.LU fcvt.s.wu/fcvt.s.lu rd, rs1 將 rs1一般暫存器中的unsigned 整數轉換為浮點數,結果寫入 rd一般暫存器。 sign-injection instructions FSGNJ.S fsgnj.s rd, rs1, rs2 rd浮點數暫存器中的數值來自 rs1浮點數暫存器,sign bit則為 rs2浮點數暫存器的 sign bit。 FSGNJN.S fsgnjn.s rd, rs1, rs2 rd浮點數暫存器中的數值來自 rs1浮點數暫存器,sign bit則為 rs2浮點數暫存器的 sign bit的相反。 FSGNJX.S fsgnjx.s rd, rs1, rs2 rd浮點數暫存器的數值來自 rs1浮點數暫存器,sign bit則為 rs1浮點數暫存器的 sign bit與 rs2浮點數暫存器的 sign bit做 xor運算。 單純 floating point與 integer之間的 move指令,與上面不同的是,只做 bit的移動,並不做浮點數與整數之間的轉換。 FMV.X.W fmv.x.w rd, rs1 將 rs1浮點數暫存器的 32-bit數值寫入 rd一般暫存器中,若在 RV64,則用 sign bit填滿最高 32-bit。 FMV.W.X fmv.w.x rd, rs1 將 rs1一般暫存器的最低 32-bit(已用IEEE 754-2008編碼好)數值寫入 rd浮點數暫存器。 ### Single-Precision Floating-Point Compare Instructions FEQ.S/FLT.S/FLE.S feq.s/flt.s/fle.s rd, rs1, rs2 將 rs1浮點數暫存器與 rs2浮點數暫存器做 eq/lt/le比較,結果寫入 rd一般暫存器。 ### Single-Precision Floating-Point Classify Instruction) FCLASS.S fclass.s rd, rs1 根據下表分類 rs1浮點數暫存器的浮點數值,結果寫入 rd一般暫存器。 ![image](https://hackmd.io/_uploads/HJiuRSxzkl.png)