2012-01-05 14 views
9

İkili bir sayıyı bir float numarasına dönüştürmek istiyorum. İşte olasılığın bir örnek:Bir ikili (dize) bir float değerine nasıl dönüştürülür?

>>> float(-0b1110) 

bana doğru çıktı verir: Maalesef

, ben yani ben float('-0b1110') gibi bir şey gerekiyor, ikili dizeleri ile çalışıyorum.
Ancak bu işe yaramazsa:

>>> float('-0b1110') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: invalid literal for float(): -0b1110 

geri ikiliye alıntı-yazdırılabilir veri bloğunu dönüştürür ve ikili veri döndürür binascii.a2b_qp(string[, header]) kullanmaya çalıştı. Ben çıkış sayı bir tamsayı ama durumları iyi anlamak

>>> float(binascii.a2b_qp('-0b1110')) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: invalid literal for float(): -0b1110 

ne numarayı 12,546 elde etmek istiyorsanız: Ama sonunda, ben de aynı hatayı alıyorum? İşlev, ikili dizge için neyi arar?

+0

12.546' 'ikili gösterimi nasıl olur - bu IEEE 754 binary32 veya binary64 nedir? Değilse, ikili nokta nasıl temsil edilir veya dizide varsayılan konumu nerede? – martineau

+0

Şamandıra 12.546'nın ikili gösterimi IEEE 754 ikili64'tür. – deedee

+2

Tamam, ancak '0b10110011000000', '-0.011' değil, '-14.0' IEEE 754 binary64 gösterimidir. – martineau

cevap

6

Diğer bir seçenek olduğunu yapmak için

from ast import literal_eval 

float_str = "-0b101010101" 
result = float(literal_eval(float_str)) 

Yerleşik "eval" in aksine, literal_eval, Python editörlerini yalnızca ayrıştırabildiği ve ifadeleri yürütmeyeceği için kullanıcı girişlerinde bile çalıştırılmasının güvenli olduğu anlamına gelir.

6
float(int('-0b1110',0)) 

Bu benim için çalışıyor.

Tamsayı yerine bir kayan nokta sayısını temsil eden bir 64-bit dizginiz varsa, üç adımlı bir dönüşüm gerçekleştirebilirsiniz - ilk adım dize bir tamsayıya dönüştürür, ikincisi onu 8'e dönüştürür Bayt dizgisi, üçüncü ise bu bitleri bir float olarak yeniden yorumluyor.

>>> import struct 
>>> s = '0b0100000000101001000101111000110101001111110111110011101101100100' 
>>> q = int(s, 0) 
>>> b8 = struct.pack('Q', q) 
>>> struct.unpack('d', b8)[0] 
12.546 

Tabii ki tüm bu adımları tek bir satırda birleştirebilirsiniz.

>>> s2 = '0b1100000000101100000000000000000000000000000000000000000000000000' 
>>> struct.unpack('d', struct.pack('Q', int(s2, 0)))[0] 
-14.0 
+0

wikipedia 0 10000000 10010010000111111011011'e göre bu, 24 bit hassasiyet için pi'nin yuvarlatılmış değeridir. >>> float (int ('0b01000000010010010000111111011011', 0)) 1078530011.0 –

+0

huh ???????????? – wim

+0

@wim http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers Aksi takdirde, eğer tamsayı kısmını alabiliyorsa, float'a dönüştürmenin anlamı nedir? –

0

Değerlendirmeyi ('') kullanabilir ve gerekirse bir kayan nokta olarak kullanabilirsiniz. Örnek:

>> eval('-0b1110') 
-14 
>> float(eval('-0b1110')) 
-14.0 
+0

İyi bir tane, ama ast.literal_eval'a cevabımdan bakın - kemerin altında olması ilginç bir oyun. – jsbueno

+1

evet, değerlendirme kötüdür – wim

0

You tabanını 2 ayarlayarak bir int dize biçiminde bir ikili sayı dönüştürebilirsiniz dahili int([x[, base]]) fonksiyonu, ancak 0b ilk kurtulmak gerekir. Daha sonra nihai sonuç almak için float() içine sonucu geçirebilirsiniz:

>>> s = '-0b1110' 
>>> float(int(s.replace('0b', ''), 2)) 
-14.0 

düzenleme: Görünüşe 0b kurtulmak aşağıda Python 2.5 ve üzerinde sadece gerekli olduğu, Mark'ın cevabı Python 2.6 benim için çalışıyor ama burada ben Python 2.5 gördükleri şeydir:

>>> int('-0b1110', 2) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: invalid literal for int() with base 2: '-0b1110' 
6

Yorumlarınızdan birinde, ikili sayının 8 bayt uzunluğunda IEEE 754 binary64 biçiminde bir kayan olduğunu gösterdiğini belirttiniz.Ancak bu, örnek olarak gösterdiğiniz -0b1110 değeriyle tutarsızdır, dolayısıyla onu yok saydım ve aşağıda gösterilen yanıtı test etmek için örnek giriş verileriyle uygun biçimde kendi formatımı kullandım.

Esas olarak, ikili dizgenin bir tamsayı değerine dönüştürülmesi, sonra da bir kayan nokta değerine son dönüşümü için struct.unpack()'a geçirilen bir ham bayt dizisine dönüştürülmesidir. Aşağıda gösterilen işlev bin_to_float() işlemi yönlendirir. Gösterilmemesine rağmen, ikili giriş dizgisi argümanları '0b' ile öneklenebilir.

import struct 

def bin_to_float(b): 
    """ Convert binary string to a float. """ 
    bf = int_to_bytes(int(b, 2), 8) # 8 bytes needed for IEEE 754 binary64 
    return struct.unpack('>d', bf)[0] 

def int_to_bytes(n, minlen=0): # helper function 
    """ Int/long to byte string. """ 
    nbits = n.bit_length() + (1 if n < 0 else 0) # plus one for any sign bit 
    nbytes = (nbits+7) // 8 # number of whole bytes 
    b = bytearray() 
    for _ in range(nbytes): 
     b.append(n & 0xff) 
     n >>= 8 
    if minlen and len(b) < minlen: # zero pad? 
     b.extend([0] * (minlen-len(b))) 
    return bytearray(reversed(b)) # high bytes first 

# tests 

def float_to_bin(f): 
    """ Convert a float into a binary string. """ 
    ba = struct.pack('>d', f) 
    ba = bytearray(ba) # convert string to bytearray - not needed in py3 
    s = ''.join('{:08b}'.format(b) for b in ba) 
    return s[:-1].lstrip('0') + s[0] # strip all leading zeros except for last 

for f in 0.0, 1.0, -14.0, 12.546, 3.141593: 
    binary = float_to_bin(f) 
    print('float_to_bin(%f): %r' % (f, binary)) 
    float = bin_to_float(binary) 
    print('bin_to_float(%r): %f' % (binary, float)) 
    print('') 

Çıktı:

float_to_bin(0.000000): '0' 
bin_to_float('0'): 0.000000 

float_to_bin(1.000000): '11111111110000000000000000000000000000000000000000000000000000' 
bin_to_float('11111111110000000000000000000000000000000000000000000000000000'): 1.000000 

float_to_bin(-14.000000): '1100000000101100000000000000000000000000000000000000000000000000' 
bin_to_float('1100000000101100000000000000000000000000000000000000000000000000'): -14.000000 

float_to_bin(12.546000): '100000000101001000101111000110101001111110111110011101101100100' 
bin_to_float('100000000101001000101111000110101001111110111110011101101100100'): 12.546000 

float_to_bin(3.141593): '100000000001001001000011111101110000010110000101011110101111111' 
bin_to_float('100000000001001001000011111101110000010110000101011110101111111'): 3.141593 
+1

Bu harika. Tam olarak aradığım şey, teşekkür ederim! – Savara

0

Bu benim için çalışıyor. Python3.4 ile test edilmiştir:

def float_to_bin(num): 
    return bin(struct.unpack('!I', struct.pack('!f', num))[0])[2:].zfill(32) 

def bin_to_float(binary): 
    return struct.unpack('!f',struct.pack('!I', int(binary, 2)))[0] 

float_to_bin(bin_to_float(float_to_bin(123.123))) == float_to_bin(123.123) 
>>> True 
İlgili konular