Python 浮点到二进制

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4838994/
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-08-18 17:45:36  来源:igfitidea点击:

Float to binary

pythonbinaryfloating-point

提问by Ant

I'm trying to convert a floating point number to binary representation; how can I achieve this? My goal is, however, not to be limited by 2m so I'm hoping for something that could be easily extended to any base (3, 4, 8) ecc.

我正在尝试将浮点数转换为二进制表示;我怎样才能做到这一点?然而,我的目标是不受 2m 的限制,所以我希望可以轻松扩展到任何基础(3、4、8)ecc。

I've got a straightforward implementation so far for integers:

到目前为止,我有一个简单的整数实现:

import string

LETTER = '0123456789' + string.ascii_lowercase
def convert_int(num, base):
    if base == 1:
        print "WARNING! ASKING FOR BASE = 1"
        return '1' * num if num != 0 else '0'

    if base > 36: raise ValueError('base must be >= 1 and <= 36')

    num, rest = divmod(num, base)
    rest = [LETTER[rest]]
    while num >= base:
        num, r = divmod(num, base)
        rest.append(LETTER[r])
    rest.reverse()
    return (LETTER[num] if num else '') + ''.join(str(x) for x in rest)

any help appreciated :)

任何帮助表示赞赏:)

edit:

编辑:

def convert_float(num, base, digits=None):
    num = float(num)
    if digits is None: digits = 6

    num = int(round(num * pow(base, digits)))
    num = convert_int(num, base)
    num = num[:-digits] + '.' + num[:digits]
    if num.startswith('.'): num = '0' + num
    return num

is that right? why do i get this behaviour?

那正确吗?为什么我会得到这种行为?

>>> convert_float(1289.2893, 16)
'509.5094a0'
>>> float.hex(1289.2983)
'0x1.42531758e2196p+10'

p.s. How to convert float number to Binary?

ps 如何将浮点数转换为二进制?

I've read that discussion, but I don't get the answer.. I mean, does it work only for 0.25, 0.125? and I dont understand the phrase 'must be in reverse order'...

我读过那个讨论,但我没有得到答案..我的意思是,它只适用于 0.25、0.125 吗?我不明白“必须以相反的顺序”这句话......

采纳答案by stmi

Next answer with a bit of theory.

下一个回答有点理论。

Explanation below does not explain IEEE Floating Point standard only general ideas concerning representation of floating point numbers

下面的解释不解释 IEEE 浮点标准,只是关于浮点数表示的一般思想

Every float number is represented as a fractional part multiplied by an exponent multiplied by a sign. Additionally there is so called bias for exponent, which will be explained bellow.

每个浮点数都表示为小数部分乘以指数乘以符号。此外,还有所谓的指数偏差,这将在下面解释。

So we have

所以我们有

  1. Sign bit
  2. Fractional part digits
  3. Exponent part digits
  1. 符号位
  2. 小数部分数字
  3. 指数部分数字

Example for base 2 with 8 bit fraction and 8 bit exponent

具有 8 位小数和 8 位指数的以 2 为底的示例

Bits in fraction part tell us which summands (numbers to be added) from sequence below are to be included in represented number value

小数部分中的位告诉我们下面序列中的哪些被加数(要添加的数字)将包含在表示的数值中

2^-1 + 2^-2 + 2^-3 + 2^-4 + 2^-5 + 2^-6 + 2^-7 + 2^-8

2^-1 + 2^-2 + 2^-3 + 2^-4 + 2^-5 + 2^-6 + 2^-7 + 2^-8

So if you have say 01101101 in fractional part it gives

所以如果你在小数部分说 01101101 它给出

0*2^-1 + 1*2^-2 + 1*2^-3 + 0*2^-4 + 1*2^-5 + 1*2^-6 + 0*2^-7 + 1*2^-8 = 0.42578125

0*2^-1 + 1*2^-2 + 1*2^-3 + 0*2^-4 + 1*2^-5 + 1*2^-6 + 0*2^-7 + 1 *2^-8 = 0.42578125

Now non-zero numbers that are representable that way fall between 2 ** -8 = 0.00390625 and 1 - 2**-8 = 0.99609375

现在可表示的非零数字介于 2 ** -8 = 0.00390625 和 1 - 2**-8 = 0.99609375 之间

Here the exponent part comes in. Exponent allows us to represent very big numbers by multiplying the fraction part by exponent. So if we have an 8bit exponent we can multiply the resulting fraction by numbers between 0 and 2^255.

这里出现了指数部分。指数允许我们通过将分数部分乘以指数来表示非常大的数字。因此,如果我们有一个 8 位指数,我们可以将结果分数乘以 0 到 2^255 之间的数字。

So going back to example above let's take exponent of 11000011 = 195.

所以回到上面的例子,让我们取指数 11000011 = 195。

We have fractional part of 01101101 = 0.42578125 and exponent part 11000011 = 195. It gives us the number 0.42578125 * 2^195, this is really big number.

我们有小数部分 01101101 = 0.42578125 和指数部分 11000011 = 195。它给了我们数字 0.42578125 * 2^195,这真的是一个很大的数字。

So far we can represent non-zero numbers between 2^-8 * 2^0 and (1-2^-8) * 2^255. This allows for very big numbers but not for very small numbers. In order to be able to represent small numbers we have to include so called bias in our exponent. It is a number that will be always subtracted from exponent in order to allow for representation of small numbers.

到目前为止,我们可以表示 2^-8 * 2^0 和 (1-2^-8) * 2^255 之间的非零数字。这允许非常大的数字,但不允许非常小的数字。为了能够表示小数,我们必须在指数中包含所谓的偏差。它是一个总是从指数中减去的数字,以允许表示小数。

Let's take a bias of 127. Now all exponents are subtracted 127. So numbers that can be represented are between 2^-8 * 2^(0 - 127) and (1-2^-8) * 2^(255 - 127 = 128)

让我们取 127 的偏差。现在所有指数都减去 127。所以可以表示的数字介于 2^-8 * 2^(0 - 127) 和 (1-2^-8) * 2^(255 - 127) 之间= 128)

Example number is now 0.42578125 * 2^(195-127 = 68) which is still pretty big.

示例数字现在是 0.42578125 * 2^(195-127 = 68) 这仍然很大。

Example ends

示例结束

In order to understand this better try to experiment with different bases and sizes for fractional and exponential part. At beginning don't try with odd bases because it only complicates things necessary.

为了更好地理解这一点,请尝试对分数和指数部分使用不同的基数和大小进行试验。一开始不要尝试奇怪的基础,因为它只会使必要的事情复杂化。

Once you grasp how this representation works you should be able to write code to obtain representation of any number in any base, fractional/exponential part combination.

一旦掌握了这种表示的工作原理,您应该能够编写代码来获得任何基数、分数/指数部分组合中的任何数字的表示。

回答by dan04

If you want to convert a floatto a string with ddigits after the decimalradix point:

如果要将 a 转换为小数点float带有d数字的字符串:

  1. Multiply the number by base**d.
  2. Round to the nearest integer.
  3. Convert the integer to a string.
  4. Insert the .character ddigits before the end.
  1. 乘以数字base**d
  2. 四舍五入到最接近的整数。
  3. 将整数转换为字符串。
  4. 在末尾插入.字符d数字。

For example, to represent 0.1 in base 12 with 4 decimaldozenal places,

例如,要表示以 12 为底的 0.1 有 4个小数位,

  1. 0.1 × 124= 2073.6
  2. Round to nearest integer → 2074
  3. Convert to string → 124A
  4. Add radix point → 0.124A
  1. 0.1 × 12 4= 2073.6
  2. 舍入到最接近的整数 → 2074
  3. 转换为字符串 → 124A
  4. 添加小数点 → 0.124A

回答by stmi

For floats there is built-in method hex().

对于浮点数,有内置方法 hex()。

http://docs.python.org/library/stdtypes.html#float.hex

http://docs.python.org/library/stdtypes.html#float.hex

It gives you the hexadecimal representation of a given number. And translation form hex to binary is trivial.

它为您提供给定数字的十六进制表示。将十六进制转换为二进制很简单。

For example:

例如:

In [15]: float.hex(1.25)
Out[15]: '0x1.4000000000000p+0'

In [16]: float.hex(8.25)
Out[16]: '0x1.0800000000000p+3'

回答by S James S Stapleton

This isn't the same style of binary representation that you want, but this will convert an IEEE 754 into it's sign, mantissa and base, which can be used to create a hex representation in a fairly straightforward fashion. Note that the 'value' of the mantissa is 1+BINARY, where BINARY is the binary representation - hence the -1 in the return.

这与您想要的二进制表示形式不同,但这会将 IEEE 754 转换为它的符号、尾数和基数,可用于以相当简单的方式创建十六进制表示。请注意,尾数的“值”是 1+BINARY,其中 BINARY 是二进制表示 - 因此返回值为 -1。

I wrote this code and am declaring it public domain.

我写了这段代码并宣布它为公共领域。

    def disect_float(f):
      f = float(f); #fixes passing integers
      sign = 0x00; #positive
      exp = 0;
      mant = 0;
      if(f < 0): #make f positive, store the sign
        sign = '-'; #negative
        f = -f;
      #get the mantissa by itself
      while(f % 1 > 0): #exp is positive
        f*=2
        exp+=1
      #while(f % 1 > 0):
      tf = f/2;
      while(tf % 1 <= 0): #exp is negative
        exp-=1;
        f=tf;
        tf=f/2;
        if(exp < -1024): break;
      mant=int(f);
      return sign, mant-1, exp;

回答by Ozbolt

Answering the title directly and using float.hex, which uses 64bit IEE754, one could write this method:

直接回答题目,使用float.hex,使用64位IEE754,可以这样写:

def float_to_bin(x):
  if x == 0:
    return "0" * 64
  w, sign = (float.hex(x), 0) if x > 0 else (float.hex(x)[1:], 1)
  mantissa, exp = int(w[4:17], 16), int(w[18:])
  return "{}{:011b}{:052b}".format(sign, exp + 1023, mantissa)

float_to_bin(-0.001) # '1011111101010000000010110011111101011000011011100110110100101010'

Note however, this does not work for NaN and Inf.

但是请注意,这不适用于 NaN 和 Inf。

回答by kuldeep725

There is one trick that i observed that we can do using simple string manipulations. I felt this method to be simpler than other methods that i came across.

我观察到一个技巧,我们可以使用简单的字符串操作来完成。我觉得这种方法比我遇到的其他方法更简单。

s = "1101.0101"
s1, s2 = s.split(".")
s1 = int(s1, 2)
s2 = int(s2, 2)/(2**len(s2))
x = s1+s2
print(x)

Output :

输出 :

13.3125

Hope it will be helpful to someone.

希望它会对某人有所帮助。