C语言 如何规范尾数

6fe3ivhb  于 8个月前  发布在  其他
关注(0)|答案(5)|浏览(144)

我试图将一个int转换为一个自定义浮点数,其中用户指定为exp和尾数保留的位数。
我的函数接受一个int valueint exp,将数字表示为 * value * 2exp*。例如,value = 12和exp = 4将返回192。
更改这些内容的流程是什么?
它是“移动二进制点并调整指数”,但我不知道这是什么意思。我不明白指数偏差是什么。我唯一知道的是,你在指数上加了一个数字,但我不明白为什么。

b91juud3

b91juud31#

当我们强制浮点数尾数的整数部分为1,小数部分为任意值时,浮点数就是 * 正规化的 *。
例如,如果我们取数字13.25,在二进制中是1101.011101将是整数部分,而01将是分数部分。
我可以将13.25表示为1101.01*(2^0),但它没有被规范化,因为整数部分不是1但是,如果我们将指数增加1,则允许将尾数右移一位:

1101.01*(2^0)
= 110.101*(2^1)
= 11.0101*(2^2)
= 1.10101*(2^3)

字符串
此表示1.10101*(2^3)13.25的规范化形式。
也就是说,我们知道规范化的浮点数**总是以1.fffffff * (2^exp)**的形式出现
为了提高效率,我们不需要把1的整数部分存储在二进制表示中,我们只是假装它在那里,所以如果我们给予你定制的浮点型尾数5位,我们就会知道10100位实际上代表的是1.10100
下面是一个使用标准23位尾数的示例:


的数据
至于指数偏差,让我们看一下标准的32位float,它分为3部分:1个符号位、8个指数位和23个尾数位:

s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm


指数0000000011111111有特殊的用途(比如表示InfNaN),所以用8个指数位,我们可以表示254个不同的指数,比如说2^12^254,但是如果我们想表示2^-3呢?我们如何得到负指数?
该格式通过自动从指数中减去127来解决此问题。因此:

  • 0000 0001将是1 -127 = -126
  • 0010 1101将是45 -127 = -82
  • 0111 1111将是127-127 = 0
  • 1001 0010将是136-127 = 9

这会将指数范围从2^1 ... 2^254更改为2^-126 ... 2^+127,以便我们可以表示负指数。

mwecs4sa

mwecs4sa2#

Tommy -- chux和eigenchris,以及其他人沿着提供了很好的答案,但是如果我正确地看待你的评论,你似乎仍然在努力解决“我如何获取这些信息,然后使用这些信息创建一个自定义的浮点表示,其中用户指定指数的位数?“你别难过,前面十几次都是一清二楚,我想我可以试着把它弄清楚。
您熟悉IEEE 754-单精度浮点表示:

IEEE-754 Single Precision Floating Point Representation of (13.25)

  0 1 0 0 0 0 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
 |s|      exp      |                  mantissa                   |

字符串
1-bit sign-bit8-bit biased exponent(以8位多余127表示法)和剩余的23-bit mantissa
当您允许用户选择指数中的位数时,您将不得不修改指数表示法以使用新的用户选择的限制。

这会改变什么

  • 是否会改变sign-bit处理--
  • 它会改变mantissa处理--(您仍然会将尾数/有效位转换为“隐藏位”格式)。

所以你唯一需要关注的是exponent handling
你会怎么做?回想一下,当前的8位指数采用的是所谓的excess-127表示法(其中127表示7位的最大值,允许在当前8-bit限制内包含和表示任何偏差。如果您的用户选择6位作为指数大小,那么是什么?您必须提供一个类似的方法,以确保您有一个固定的数字来表示新的**excess-##**表示法,该表示法将在用户限制范围内工作。
6-bit用户限制为例,则可以尝试选择无偏指数值为31(可以用5-bits表示的最大值)。(以上述13.25为例).你的二进制数表示为1101.01,你将十进制数3 positions to the left移动到1.10101,得到3的指数偏差。
6-bit exponent的例子中,你可以添加3 + 31来获得指数的excess-31 notation100010,然后将尾数放在“隐藏位”格式中(即从1.10101中删除前导1,从而产生新的自定义Tommy Precision表示:

IEEE-754 Tommy Precision Floating Point Representation of (13.25)

  0 1 0 0 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
 |s|    exp    |                    mantissa                     |


使用1-bit sign-bit6-bit biased exponent(采用6位excess-31表示法)和剩余的25-bit mantissa
同样的规则也适用于从上面的符号中反转浮点数的过程。(只是使用31而不是127来支持指数的偏差)
希望这能在某种程度上有所帮助。如果你真的要允许用户选择指数大小,我看不出你还能做什么。记住,IEEE-754标准不是猜测出来的,很多很好的推理和权衡都是为了达到1-8-23符号-指数-尾数布局。然而,我认为你的练习在要求你牢固地理解标准方面做得很好。
现在完全丢失和没有解决在这个讨论中,这将对可以在这个Custom Precision Floating Point Representation中表示的数字范围产生什么影响。我没有看过它,但主要的限制似乎是减少了可以表示的MAX/MIN

qqrboqgw

qqrboqgw3#

“标准化过程”将输入转换为选择范围。
binary32期望有效数(不是尾数)在1.0 <= s < 2.0范围内,除非该数字具有最小指数。
范例:
value = 12, exp = 4是相同的
value = 12/(2*2*2), exp = 4 + 3
value = 1.5, exp = 7
由于有效位总是有一个前导位1(除非该数字有一个最小指数),因此不需要存储它。而不是将指数存储为7,而是向其添加一个偏置127。
value = 1.5 decimal --> 1.1000...000 binary --> 0.1000...000 stored binary(共23位)
exp = 7 --> bias exp 7 + 127 --> 134 decimal --> 10000110 binary
存储的二进制模式是“符号”、“隐含前导1位的有效位”和“偏置指数”的级联

0 10000110 1000...000 (1 + 8 + 23 = 32 bits)

字符串
当有偏指数为0-最小值时,隐含位为0,因此可以存储0.0这样的小数字。
当有偏指数为255-最大值时,存储的数据不再表示有限数,而是“无穷大”和“非数字”。
查看参考链接了解更多详情。

mspsb9vt

mspsb9vt4#

要回答关于“如何在代码中做到这一点”的评论:(假设它是IEEE float)
A)从IEEE浮点数中提取无符号的“指数”和“尾数”。
i)exp = 0x7F800000 & yourFloatVar;
//从浮点数中获取b1到b8位(b 0是有符号位,b 9是尾数)
ii)exp = exp >> 23;//右移,因此该指数是右向的
iii)exp += 127;//添加偏置(127仅适用于32位)
iv)mantissa = 0x007FFFFF & yourFloatVar;//从float取最后23位
B)归一化
(一)

while(true)
{
    if( ((mantissa & 0xC0000000) != 0x80000000)
         &&((mantissa & 0xC0000000) != 0x40000000) )
    {
        mantissa = mantissa << 1;
        exponent--;
    }
    else //AKA the float has been normalized
    {
        break;
    }
}

字符串
如果前导2位不是'01'或'10'(这是2的补码的属性-规格化的条件),则移过尾数并递减指数。
我想指出的是,这并不是最有效的算法;我只是想让步骤清楚。希望我没有错过任何东西!

egmofgnx

egmofgnx5#

要规范化尾数,请将小数点放在最左边的非零数字的左边
例如
以标准化形式表示10.11底2
= 0.1011基数2 * 2的二次幂
2的基数是因为你在处理二进制数,+ve 2的幂是因为你把小数点左移了两次。记住,只有4位用于mantizza
所以mantizza应该是1011

相关问题