如何将浮点数转换为非标准编码

时间:2010-08-30 03:53:23

标签: c++ c cocoa math types

我正在编写一个创建ICC颜色格式的程序。这些格式指定一个名为s15Fixed16Number的数据类型,它具有符号位,15个整数位和16个小数位。 IEEE 754 32位浮点数具有符号位,8个指数位和23个小数位。

我需要从文本框中获取输入,并将它们转换为s15Fixed16Number。有些搜索在Google图书上显示this,但这是在谈论将十进制数转换为s15Fixed16Number。我想我可以使用链接中解释的方法,但我还没有做任何测试来确定它的准确性。我想我也可以尝试从文本框转换字符输入,但我还没有想过那么多。

我正在使用Cocoa,但我不认为这很重要;任何C函数都应该有效。以下是s15Fixed16Number格式的一些示例值:

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

我想从数值计算类开始已经有一段时间了!

2 个答案:

答案 0 :(得分: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

编辑:更正&amp;到|

答案 1 :(得分: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 16 )。要从浮点值形成这样的理性,您只需乘以分母。然后它只是一个适当的舍入问题,并截断为整数类型。

标准选择了他们所做的表格,因为如果你的系统使用2的补码整数运算,这就行了。虽然最左边的位确实代表符号,但它不是浮点表示中使用的符号位。

如果您的计算是真正的float而不是double,您会发现计算中的精确度不如满量程附近的数字的固定点值。如果以double计算,那么计算中的精度将始终高于结果。

修改

明显的最新规范from the ICC规范ICC.1:2004-10(配置文件版本4.2.0.0)。第5.1.3节:

  

5.1.3 s15Fixed16Number

     

固定的带符号的4字节/ 32位数量   16个小数位,如表3所示。

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

除了小数点表示的局部偏好之外,这些值完全符合我的理解,即表示只是带符号2的补码整数,应除以65536以得到它们的值。

表示的自然转换只是乘以65536,并从中简单地除以。选择合适的舍入规则是一个优先考虑的问题。

满量程范围从-32768.0(0x80000000)到大约32767.9999847412(0x7fffffff),包括在内。

我同意,如果规范恰好以十六进制显示任何负值的表示,那将更清楚。我浏览了整个文档,我发现的十进制和十六进制表示的唯一值是CIE XYZ色度坐标,根据定义范围从0到1,因此无法作为示例负值。