C语言 如何标准化尾数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28800565/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 11:46:18  来源:igfitidea点击:

How to normalize a mantissa

cfloating-pointdoublenormalization

提问by Tommy K

I'm trying to convert an intinto a custom float, in which the user specifies the amount of bits reserved for the exp and mantissa, but I don't understand how the conversion works. My function takes in an int value and and int exp to represent the number (value * 2^exp) i.e value = 12, exp = 4, returns 192. but I don't understand the process I need to do to change these. I've been looking at this for days and playing with IEEE converter web apps but I just don't understand what the normalization process is. Like I see that its "move the binary point and adjust the exponent" but I have no idea what this means, can anyone give me an example to go off of? Also I don't understand what the exponent bias is. The only info I have is that you just add a number to your exponent but I don't understand why. I've been searching Google for an example I can understand but this just isn't making any sense to me

我正在尝试转换 int转换为自定义浮点数,其中用户指定为 exp 和尾数保留的位数,但我不明白转换是如何工作的。我的函数接受一个 int 值和 int exp 来表示数字(值 * 2^exp),即 value = 12,exp = 4,返回 192。但我不明白我需要做的过程来改变这些。我已经研究了几天并使用 IEEE 转换器网络应用程序,但我只是不明白规范化过程是什么。就像我看到它“移动二进制小数点并调整指数”一样,但我不知道这是什么意思,谁能给我举个例子?我也不明白指数偏差是什么。我唯一的信息是你只是在指数上加了一个数字,但我不明白为什么。一世'

回答by eigenchris

A floating point number is normalizedwhen we force the integer part of its mantissa to be exactly 1and allow its fraction part to be whatever we like.

当我们强制其尾数的整数部分精确并允许其小数部分为我们喜欢的任何值时,浮点数就被标准化了1

For example, if we were to take the number 13.25, which is 1101.01in binary, 1101would be the integer part and 01would be the fraction part.

例如,如果我们取二进制数字13.25,它将是整数部分,将是小数部分。1101.01110101

I could represent 13.25as 1101.01*(2^0), but this isn't normalized because the integer part is not 1. However, we are allowed to shift the mantissa to the right one digit if we increase the exponent by 1:

我可以表示13.251101.01*(2^0),但这不是标准化的,因为整数部分不是1但是,如果我们将指数增加 1,我们可以将尾数向右移动一位:

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

This representation 1.10101*(2^3)is the normalized form of 13.25.

这种表示1.10101*(2^3)是 的规范化形式13.25



That said, we know that normalized floating point numbers will always come in the form 1.fffffff * (2^exp)

也就是说,我们知道规范化的浮点数将始终采用以下形式1.fffffff * (2^exp)

For efficiency's sake, we don't bother storing the 1integer part in the binary representation itself, we just pretend it's there. So if we were to give your custom-made float type 5 bits for the mantissa, we would know the bits 10100would actually stand for 1.10100.

为了效率,我们不费心1在二进制表示中存储整数部分,我们只是假装它在那里。因此,如果我们为您的尾数提供定制的浮点类型 5 位,我们就会知道这些位10100实际上代表1.10100.

Here is an example with the standard 23-bit mantissa:

以下是标准 23 位尾数的示例:

enter image description here

在此处输入图片说明



As for the exponent bias, let's take a look at the standard 32-bit floatformat, which is broken into 3 parts: 1 sign bit, 8 exponent bits, and 23 mantissa bits:

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

s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm

The exponents 00000000and 11111111have special purposes (like representing Infand NaN), so with 8 exponent bits, we could represent 254 different exponents, say 2^1to 2^254, for example. But what if we want to represent 2^-3? How do we get negative exponents?

该指数0000000011111111具有特殊用途(如代表InfNaN),所以用8个指数位,我们可以表示254个不同的指数,说2^12^254,例如。但是如果我们想表示2^-3呢?我们如何得到负指数?

The format fixes this problem by automatically subtracting 127 from the exponent. Therefore:

该格式通过自动从指数中减去 127 来解决这个问题。所以:

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

This changes the exponent range from 2^1 ... 2^254to 2^-126 ... 2^+127so we can represent negative exponents.

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

回答by David C. Rankin

Tommy -- chux and eigenchris, along with the others have provided excellent answers, but if I am looking at your comments correctly, you still seem to be struggling with the nuts-and-bolts of "how would I take this info and then use this in creating a custom float representation where the user specifies the amount of bits for the exponent?" Don't feel bad, it is a clear as mud the first dozen times you go through it. I think I can take a stab at clearing it up.

汤米——chux 和 eigenchris 以及其他人提供了很好的答案,但如果我正确地看待你的评论,你似乎仍然在为“我将如何获取这些信息然后使用这是在创建自定义浮点表示,其中用户指定指数的位数?” 别难过,你在前十几次穿过它时,它就像泥一样清晰。我想我可以尝试一下清理它。

You are familiar with the IEEE754-Single-Precision-Floating-Point representation of:

您熟悉以下 IEEE754-Single-Precision-Floating-Point 表示:

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                   |

That the 1-bit sign-bit, 8-bit biased exponent(in 8-bit excess-127 notation), and the remaining 23-bit mantissa.

1-bit sign-bit, 8-bit biased exponent(以 8 位超额 127 表示法),以及其余的23-bit mantissa.

When you allow the user to choose the number of bits in the exponent, you are going to have to reworkthe exponent notation to work with the new user-chosen limit.

当您允许用户选择指数中的位数时,您将不得不重新编写指数符号以使用新的用户选择限制。

What will that change?

那会改变什么?

  • Will it change the sign-bithandling -- No.

  • Will it change the mantissahandling -- No(you will still convert the mantissa/significand to "hidden bit" format).

  • 它会改变sign-bit处理方式吗?不会

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

So the only thing you need to focus on is exponent handling.

所以你唯一需要关注的是exponent handling

How would you approach this? Recall, the current 8-bit exponent is in what is called excess-127 notation(where 127 represents the largest value for 7bits allowing any bias to be contained and expressed within the current 8-bitlimit. If your user chooses 6 bits as the exponent size, then what? You will have to provide a similar method to insure you have a fixed number to represent your new excess-##notation that will work within the user limit.

你会如何处理这个问题?回想一下,当前的 8 位指数采用所谓的超额 127 表示法(其中 127 表示7允许在当前8-bit限制内包含和表达任何偏差的位的最大值。如果您的用户选择 6 位作为指数大小,那又怎样呢?您必须提供一个类似的方法来确保您有一个固定的数字来表示您的新超额-##符号,该符号将在用户限制内工作。

Take a 6-bituser limit, then a choice for the unbiased exponent value could be tried as 31(the largest values that can be represented in 5-bits). To that you could apply the same logic (taking the 13.25 example above). Your binary representation for the number is 1101.01to which you move the decimal 3 positions to the leftto get 1.10101which gives you an exponent bias of 3.

6-bit用户限制,然后可以尝试选择无偏指数值31(可以在 中表示的最大值5-bits)。对此,您可以应用相同的逻辑(以上面的 13.25 为例)。数字的二进制表示是1101.01将小数3 positions to the left移到1.10101哪个位置,从而得到 的指数偏差3

In your 6-bit exponentcase you would add 3 + 31to obtain your excess-31 notationfor the exponent: 100010, then put the mantissa in "hidden bit" format (i.e. drop the leading 1from 1.10101resulting in your new custom Tommy Precision Representation:

在您的6-bit exponent情况下,您将添加3 + 31以获得您excess-31 notation的指数:100010,然后将尾数置于“隐藏位”格式(即11.10101导致您的新自定义汤米精度表示中删除前导:

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                     |

With 1-bit sign-bit, 6-bit biased exponent(in 6-bit excess-31 notation), and the remaining 25-bit mantissa.

1-bit sign-bit, 6-bit biased exponent(以 6 位超额 31 表示法),其余的25-bit mantissa.

The same rules would apply to reversing the process to get your floating point number back from the above notation. (just using 31instead of 127to back the bias out of the exponent)

相同的规则适用于反转过程以从上述符号中恢复浮点数。(只是使用31而不是127支持指数的偏差)

Hopefully this helps in some way. I don't see much else you can do if you are truly going to allow for a user-selected exponent size. Remember, the IEEE-754 standard wasn't something that was guessed at and a lot of good reasoning and trade-offs went into arriving at the 1-8-23 sign-exponent-mantissa layout. However, I think your exercise does a great job at requiring you to firmly understand the standard.

希望这在某种程度上有所帮助。如果您真的要允许用户选择的指数大小,我看不到您可以做的其他事情。请记住,IEEE-754 标准不是凭空猜测的,为了达到 1-8-23 符号-指数-尾数布局,需要进行大量合理的推理和权衡。但是,我认为您的练习在要求您牢牢理解标准方面做得很好。

Now totally lost and not addressedin this discussion is what effects this would have on the range of numbers that could be represented in this Custom Precision Floating Point Representation. I haven't looked at it, but the primary limitation would seem to be a reduction in the MAX/MINthat could be represented.

现在完全丢失并且在此讨论中未解决的是这会对可以在此表示的数字范围产生什么影响Custom Precision Floating Point Representation。我没有看过它,但主要的限制似乎是可以表示的减少MAX/MIN

回答by chux - Reinstate Monica

"Normalization process" converts the inputs into a select range.

“标准化过程”将输入转换为选择范围。

binary32expects the significand (not mantissa) to be in the range 1.0 <= s < 2.0unless the number has a minimum exponent.

binary32期望有效数(不是尾数)在范围内,1.0 <= s < 2.0除非数字具有最小指数。

Example:
value = 12, exp = 4is the same as
value = 12/(2*2*2), exp = 4 + 3
value = 1.5, exp = 7

示例:
value = 12, exp = 4
value = 12/(2*2*2), exp = 4 + 3
value = 1.5, exp = 7

Since the significand always has a leading digit of 1(unless the number has a minimum exponent), there is no need to store it. And rather than storing the exponent as 7, a bias of 127 is added to it.

由于有效数总是有一个前导数字1(除非该数字具有最小指数),因此无需存储它。并且不是将指数存储为7,而是向其添加 127 的偏差。

value = 1.5 decimal --> 1.1000...000 binary --> 0.1000...000 stored binary (23 bits in all)
exp = 7 --> bias exp 7 + 127 --> 134 decimal --> 10000110 binary

值 = 1.5 十进制 --> 1.1000...000 二进制 --> 0.1000...000 存储二进制(总共 23 位)
exp = 7 --> 偏差 exp 7 + 127 --> 134 十进制 --> 10000110 二进制

The binary pattern stored is the concatenation of the "sign", "significand with a leading 1 bit implied" and a "bias exponent"

存储的二进制模式是“符号”、“隐含前导 1 位的有效数”和“偏差指数”的串联

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

When the biased exponent is 0- the minimum value, the implied bit is 0and so small numbers like 0.0can be stored.

当偏置指数是0- 最小值时,隐含位是0,因此0.0可以存储很小的数字。

When the biased exponent is 255- the maximum value, data stored no longer represents finite numbers but "infinity" and "Not-a-numbers".

当偏置指数为255- 最大值时,存储的数据不再代表有限数字,而是“无穷大”和“非数字”。

Check the referenced link for more details.

查看引用的链接以获取更多详细信息。

回答by J. Doe

To answer a comment posted on 'how to do this in code': (Assuming it's an IEEE float)

回答关于“如何在代码中执行此操作”的评论:(假设它是 IEEE 浮点数)

A) Extract an unsigned 'exponent' and 'mantissa' from the IEEE float.

A) 从 IEEE 浮点数中提取一个无符号的“指数”和“尾数”。

i) exp = 0x7F800000 & yourFloatVar;

一世) exp = 0x7F800000 & yourFloatVar;

//this takes bit b1 through b8 from the float. (b0 is the signed bit, b9 and on is the mantissa)

//这从浮点数中获取 b1 到 b8 位。(b0 是有符号位,b9 和 on 是尾数)

ii) exp = exp >> 23;//shift right so this exponent is right-oriented

ii) exp = exp >> 23;//右移,使该指数向右

iii) exp += 127;//add in the bias (127 is for 32-bit only)

iii) exp += 127;//添加偏差(127 仅适用于 32 位)

iv) mantissa = 0x007FFFFF & yourFloatVar;//take last 23 bits from float

iv) mantissa = 0x007FFFFF & yourFloatVar;//从浮点数中取出最后 23 位

B) Normalizing

B) 标准化

i)

一世)

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

if leading 2 bits aren't '01' or '10' (this is a property of 2's complement - the condition to normalize), then shift over the mantissa and decrement the exponent.

如果前导 2 位不是 '01' 或 '10'(这是 2 的补码的属性 - 归一化的条件),则移动尾数并减少指数。

I want to note that this isn't at all the most efficient algorithm for doing this; I just wanted to make the steps clear. Hope I didn't miss anything!

我想指出,这根本不是最有效的算法;我只是想把步骤说清楚。希望我没有错过任何东西!

回答by Questionare232

To normalize a mantissa you place the decimal point to the left of the leftmost non-zero digit

要标准化尾数,您将小数点放在最左边的非零数字的左侧

for example

例如

represent 10.11 base 2 in normalize form

以标准化形式表示 10.11 base 2

= 0.1011 base 2 * 2 to the second power

= 0.1011 base 2 * 2 的二次方

the base of two is because you are working with binary numbers and the power of +ve 2 is because you moved the decimal point left two times. Remember that only 4 bits are used for the mantizza

以 2 为底是因为您使用的是二进制数,而 +ve 2 的幂是因为您将小数点向左移动了两次。请记住,尾数仅使用 4 位

so the mantizza would be 1011

所以 mantizza 将是 1011