2010-08-30 63 views
6

我正在編寫一個程序來創建ICC顏色格式。這些格式指定一個名爲s15Fixed16Number的數據類型,它具有一個符號位,15個整數位和16個小數位。 IEEE 754 32位浮點數有一個符號位,8個指數位和23個小數位。如何將float轉換爲非標準編碼

我需要從文本框中獲取輸入,並將它們轉換爲s15Fixed16Number。一些搜索在谷歌的書籍上出現this,但那是在談論將十進制數轉換爲s15Fixed16Number。我想我可以使用鏈接中解釋的方法,但是我還沒有做任何測試來確定這將是多麼準確。我想我也可以嘗試從文本框中轉換字符輸入,但我還沒有想過那麼多。

我正在使用可可,但我不認爲這很重要;任何C函數都可以工作。以下是s15Fixed16Number格式一些示例值:

   -32768.0 = 0x80000000 
        0 = 0x00000000 
        1.0 = 0x00010000 
32767 + (65535/65536) = 0x7FFFFFFF 

我想這是一段時間以來該數值計算類!

+0

如果示例轉換正確,那麼s15Fixed16Number沒有符號位: - 它只是標準二進制補碼簽名編碼。例如-32768.0 = 0x80000000意味着:-1.0 = 0xffff0000 – 2010-08-30 05:52:24

+0

這由ICC配置文件格式規範備份,該規範聲明s15Fixed16Number:「這種類型表示具有16個小數位的固定帶符號4字節/ 32位 位數」。它沒有說它有一個符號位,但是這個數字是有符號的。 – 2010-08-30 05:58:47

+0

該標準給出了一個編碼爲s15Fix16Number的負數的示例(假),值爲-32768.9999。這顯然超出了有效範圍。不清楚-1應該被編碼爲什麼;不清楚最小有效編碼值是多少(-32768.00000或-32767.99999)。附錄中標題中使用的類型是:'typedef long icS15Fixed16Number;'。 – 2010-08-30 06:05:50

回答

2

假設你的C環境使用2的補碼整數,那麼這比看起來簡單得多。

typedef long s1516; // 32bit 2's complement signed integer 
s1516 floattos1516(double f) { 
    return (s1516)(f * 65536. + 0.5); 
} 

該表示法是一個固定點值,有16位小數。這與分母始終爲65536(或2 )的有理數相同。爲了從浮點值中形成這樣的理性,你只需乘以分母即可。然後,它只是一個適當的四捨五入問題,並截斷整型。

該標準選擇了他們所做的形式,因爲如果您的系統使用二進制補碼整數算術運算,該標準纔有效。雖然最左邊的位確實表示符號,但它並不是在浮點表示中使用的意義上的符號位。

如果你的計算結果真的是float而不是double,你會發現你的計算精度不如在滿刻度附近的數值的固定點值。如果你在double中計算,那麼你的計算總是比結果更精確。

編輯:

的明顯最新規格可from the ICC規格ICC.1:2004-10(配置文件版本4.2.0.0)。第5.1.3節:

5.1.3 s15Fixed16Number

固定的署名爲表3所示,其具有 16小數位4字節/ 32位量。

 
Table 3 — s15Fixed16Number 
    Number    Encoding 
-32768,0    80000000h 
    0     00000000h 
    1,0    00010000h 
32767 + (65535/65536) 7FFFFFFFh 

除了一個小數點的表示局部的偏好,這些值是用我的理解完全一致的表示僅僅是符號二進制補碼整數,應該由65536分,以得到他們的價值觀。

表示的自然轉換隻是乘以65536,並從它簡單地分割。選擇合適的舍入規則是一個偏好問題。

滿量程範圍從-32768.0(0x80000000)到約32767.9999847412(0x7fffffff)(含)。

我同意,如果規範發生在以十六進制表示任何負值的情況下會更清楚。我瀏覽了整個文檔,我發現的只有十進制和十六進制表示的值都是CIE XYZ色度座標,其定義範圍從0到1,因此不能作爲示例負值。

+0

當插入我的測試框架(作爲輸出中的額外列)時,您的代碼缺少錯誤檢查以發現範圍問題。而且,當輸入爲負時(結果爲-1.0時,結果爲0xFFFF0001)結果嚴重錯誤。 +0.5的舍入會導致我的答案略有偏差,但由於它的原因,你可能會比我更好。 – 2010-08-30 05:53:58

+0

-1.0將完全是0xFFFF0000,假設編碼是我所理解的。然而,收尾可能不是最好的答案。我應該將這個特定的片段標記爲未經測試,但我使用它的片段來定期從浮點轉換爲固定點。 – RBerteig 2010-08-30 06:32:41

+0

@Jonathon,我想你已經在思考規範了。當我閱讀它時,它只能有簡單和自然的含義,並且引用的樣本值是一致的。 – RBerteig 2010-08-30 07:09:24

2

不要忘記浮子的內部表現。定點值只是整數,具有恆定的比例因子。請記住,浮點數的精度比目標格式的精度要高,因此對於大數值,期望值可能會在較低的9位中關閉。

//s15Fixed16Number is presumably typedef'ed to unsigned int 
float foo = 1.0f; 
int fooFixedSigned = (int)(foo * 65536); 
s15Fixed16Number fooFixed = (s15Fixed16Number)(abs(fooFixedSigned)); 
if (foo < 0) fooFixed = fooFixed | (1 << 31); 
//you'll also need to explicitly check for overflows and underflows and handle them however is appropriate to your situation 

編輯:更正&至|

+0

正如Alan所示,可以通過乘以或除以單位值來將固定點值轉換爲浮點值並從浮點值轉換。這種格式通過指定一個符號位來引發一個小的扭曲。 – 2010-08-30 04:58:16

+0

你應該使用'long'而不是'int' - 前者至少有32位,而後者只能保證有16位。 – caf 2010-08-30 05:19:52

+0

對不起,沒有。關閉,但不是。該表示明確表示它是2的補碼。你沒有通過獲取絕對值得到。此外,嘗試使用按位AND運算符來設置符號位將清除除*符號位以外的每個位*。 – RBerteig 2010-08-30 05:33:19