2016-05-08 31 views
2

Ich habe float 32 Zahlen (sagen wir positive Zahlen) im numply Format. Ich möchte sie in Festkommazahlen mit einer vordefinierten Anzahl von Bits konvertieren, um die Genauigkeit zu reduzieren.Wie benutze ich Python, um eine Gleitkommazahl in einen festen Punkt mit vordefinierter Anzahl von Bits zu konvertieren

Zum Beispiel wird Nummer 3.1415926 3.25 in Matlab mit der Funktion num2fixpt. Der Befehl lautet num2fixpt (3.1415926, sfix (5), 2^(1 + 2-5), 'Nearest', 'on'), was 3 Bits für einen ganzzahligen Teil, 2 Bits für einen Bruchteil bedeutet.

Kann ich das gleiche tun mit Python

+0

Was ist Ihr Endziel hier? –

+0

Ich möchte nicht, dass die Nummer zu präzise ist. Zum Beispiel, um den Fall mit Festkomma-Digitalsignalprozessor zu simulieren. Ich möchte, dass die Gleitkommazahl mit weniger Genauigkeit im Festkommaformat gespeichert wird. – tuming1990

Antwort

3

Sie es tun können, wenn Sie verstehen, wie IEEE Gleitkommadarstellung funktioniert. Im Grunde müssen Sie LONG in ein Python konvertieren, bitweise Operatoren und dann zurückverwandeln. Zum Beispiel:

import time,struct,math 
long2bits = lambda L: ("".join([str(int(1 << i & L > 0)) for i in range(64)]))[::-1] 
double2long = lambda d: struct.unpack("Q",struct.pack("d",d))[0] 
double2bits = lambda d: long2bits(double2long(d)) 
long2double = lambda L: struct.unpack('d',struct.pack('Q',L))[0] 
bits2double = lambda b: long2double(bits2long(b)) 
bits2long=lambda z:sum([bool(z[i] == '1')*2**(len(z)-i-1) for i in range(len(z))[::-1]]) 

>>> pi = 3.1415926 
>>> double2bits(pi) 
'0100000000001001001000011111101101001101000100101101100001001010' 
>>> bits2long('1111111111111111000000000000000000000000000000000000000000000000') 
18446462598732840960L 
>>> double2long(pi) 
4614256656431372362 
>>> long2double(double2long(pi) & 18446462598732840960L) 
3.125 
>>> 

def rshift(x,n=1): 
    while n > 0: 
     x = 9223372036854775808L | (x >> 1) 
     n -= 1 
    return x 

>>> L = bits2long('1'*12 + '0'*52) 
>>> L 
18442240474082181120L 
>>> long2double(rshift(L,0) & double2long(pi)) 
2.0 
>>> long2double(rshift(L,1) & double2long(pi)) 
3.0 
>>> long2double(rshift(L,4) & double2long(pi)) 
3.125 
>>> long2double(rshift(L,7) & double2long(pi)) 
3.140625 

Dadurch wird nur die Anzahl der Bits abgeschnitten, nicht um sie herum. Die rshift-Funktion ist notwendig, weil der Operator für die rechte Verschiebung von Python das leere linke Bit mit einer Null füllt. Siehe eine Beschreibung des IEEE-Gleitkommawerts here.

1

Sie können ohne explizite Typkonvertierungen auf binäre feste Präzision runden das eine Menge Dolmetscher-Overhead zu erzeugen neigen:

import numpy as np 

n_bits = 2 
f = (1 << n_bits) 

a = np.linspace(1, 2, 11) 
a_fix = np.round(a*f)*(1.0/f) 

print a 
print a_fix 

Ergebnisse in

[ 1. 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2. ] 
[ 1. 1. 1.25 1.25 1.5 1.5 1.5 1.75 1.75 2. 2. ] 

Das Beispiel verwendet numpy, aber das ist nur um eine Liste von Beispielwerten zu erzeugen. Python eingebaute in round für einzelne Werte genauso gut funktionieren:

x=3.1415926 
x_fix = round(x*f)/float(f) 
print x_fix 

anzumerken, dass sowohl f und 1,0/f eine exakte Darstellung haben Gleitkommazahl; daher sind Multiplikation und Division genau, ohne Rundungsfehler. Beachten Sie auch, dass die Multiplikation mit 1.0/f bei großen Arrays etwa 3x schneller ist als die Division.

Dieser Ansatz steuert nicht die Anzahl der Bits für den ganzzahligen Teil. Wenn Sie also die Zahlen begrenzen oder umbrechen möchten, wenn sie zu groß sind, müssen Sie etwas mehr verschieben.