float nach binary...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dinge die die welt nicht braucht :lol:

Bei meinem Emulator ist irgendwo in der nähe der Floating point Routinen des BASIC Interpreter ein bug.

Basic speichert Float Zahlen so:
exponent: 1Byte = 8 Bits (most significant bit is the sign 1=positive 0=negative)
mantissa/fraction: 4Bytes = 32 Bits
sign of mantissa: 1Byte = 8 Bits (0x00 positive, 0xff negative)
Somit entspricht es wohl nicht dem IEEE 754 binary32 Standard.
Ist anscheinend das selbe wie bei C64, siehe: http://www.c64-wiki.com/index.php/Float ... arithmetic


Nun möchte ich gern in Python eine Zahl zu dieser Speicherart konvertieren und damit rumtesten.


Als ersten Anhaltspunkt habe ich das zusammen:

Code: Alles auswählen

import struct

def convert(value):
    return struct.unpack('>l', struct.pack('>f', value))[0]

def test(value):
    print "***", value
    converted = convert(value)
    print "converted:", converted
    print "binary: {0:08b}".format(converted)


test(5.5)
test(-5.5)
Ausgabe:

Code: Alles auswählen

*** 5.5
converted: 1085276160
binary: 1000000101100000000000000000000
*** -5.5
converted: -1062207488
binary: -111111010100000000000000000000
Hilft aber irgendwie nicht weiter, weil es nicht das richtige Format ist.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Als erstes würde ich ja ein paar Referenzwerte erstellen. Also Zahlen auf dem Dragon in Bytes umwandeln und die dann auf dem PC dekodieren.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ja, das ist ja das Problem: Ich hab kaum was als Referenzen :(

Das könnte stimmen:

Code: Alles auswählen

$36 = 54

Float in ACCU (hex):
86         d8        00       00       00       00

2^(+6)
10000110   110110000 00000000 00000000 00000000 00000000
+    4     || ||
     +2    || ||
    ---    || |+ 0.03125
      6    || +- 0.0625
           |+--- 0.25
           +---- 0.5

(0.5+0.25+0.0625+0.03125)*2^6 = 54
Zu Fuß komm ich da hin:

Code: Alles auswählen

import math

def float2bin(value, bits=32, pos=1, old=[]):
    if len(old) >= bits:
        return old

    temp = 1.0 / 2 ** pos

    if value >= temp:
        old.append(1)
        return float2bin(value - temp, bits, pos + 1, old)
    else:
        old.append(0)
        return float2bin(value, bits, pos + 1, old)
    return old

def convert(value):
    print "value:", value
    mantissa, exponent = math.frexp(value)
    print "mantissa:", mantissa
    mantissa_binary = float2bin(mantissa)
    print "exponent: dez.: %i - ", exponent
    print "          binary: {0:08b}".format(exponent)
    print "mantissa_binary:", "".join(["%s" % i for i in mantissa_binary])
    return exponent, mantissa_binary


exponent, mantissa_binary = convert(54)
exponent, mantissa_binary = convert(-54)
Ausgabe:
value: 54
mantissa: 0.84375
exponent: dez.: %i - 6
binary: 00000110
mantissa_binary: 11011000000000000000000000000000
value: -54
mantissa: -0.84375
exponent: dez.: %i - 6
binary: 00000110
mantissa_binary: 11011000000000000000000000000000
Danach fehlt noch die Umwandlung. Alles wohl recht umständlich ;)
Denke float2bin() kann man auch direkt zu float2hex() umformen.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Dann erzeug Dir doch Referenzen. Auf dem Dragon, also entweder echt oder eine bestehende Emulation. Und ich würde nicht eine Binärdarstellung erzeugen sondern ganze Zahlen.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

jens hat geschrieben: Basic speichert Float Zahlen so:
exponent: 1Byte = 8 Bits (most significant bit is the sign 1=positive 0=negative)
mantissa/fraction: 4Bytes = 32 Bits
sign of mantissa: 1Byte = 8 Bits (0x00 positive, 0xff negative)
...
Werd zwar nicht schlau aus der Beschreibung, vllt. hilft Dir dieser zu Fuß Ansatz weiter:

Code: Alles auswählen

import math

lb = lambda x: math.log(x) / math.log(2)


def num2float(num):
    num = float(abs(num))
    e = int(lb(num))
    if num < 1:
        e -= 1
    rem = num
    m = 0
    bit = float(2**e)
    for _ in range(32):
        if rem and rem >= bit:
            m |= 1
            rem -= bit
        m <<= 1
        bit /= 2
    return m, e


def float2num(m, e):
    num = float(2**e)
    carry = num
    for bit in bin(m)[3:].zfill(31):
        carry /= 2
        if bit == '1':
            num += carry
    return num

if __name__ == '__main__':
    print num2float(54), float2num(*num2float(54))
    print num2float(math.pi), float2num(*num2float(math.pi)), math.pi
    print num2float(0.001), float2num(*num2float(0.001))
Ohne Referenzwerte kommst Du leider nicht weiter, da z.B. der Wertebereich der Mantisse unklar ist (habs mal mit 1 <= m < 2 angenommen).
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Erstmal der Vollständigkeitshalber, die Rekursive Version durch eine einfache Schleife ersetzt:

Code: Alles auswählen

def float2bin(value, bits=32):
    value=abs(value)
    result = []
    for pos in xrange(1, bits):
        temp = 1.0 / 2 ** pos
        if value >= temp:
            value -= temp
            result.append(1)
        else:
            result.append(0)
    return result
So ich hab mal versucht alles zusammen zu bringen:

Code: Alles auswählen

import math
import decimal


def unsigned8(x):
    """ convert a signed 8-Bit value into a unsigned value """
    if x < 0:
        x = x + 0x0100 # 0x100 == 2**8 == 256
    return x

class FloatingPoint(object):
    """
    exponent: 1Byte = 8 Bits (most significant bit is the sign 1=positive 0=negative)
    mantissa/fraction: 4Bytes = 32 Bits
    sign of mantissa: 1Byte = 8 Bits (0x00 positive, 0xff negative)
    """
    def __init__(self, value):
        self.value = decimal.Decimal(value)
        self.mantissa, self.exponent = math.frexp(value)
        self.exponent_byte = unsigned8(self.exponent-128)
        if self.mantissa>=0:
            self.mantissa_sign = 0x00
        else:
            self.mantissa_sign = 0xff
        self.mantissa_bytes = self.mantissa2bytes(self.mantissa)

    def mantissa2bytes(self, value, bytes=4):
        value=decimal.Decimal(abs(value))
        result = []
        pos = 0
        for byte_no in xrange(bytes):
            current_byte = 0
            for bit_no in reversed(xrange(1,8)):
                pos +=1
                bit_value = decimal.Decimal(1.0) / decimal.Decimal(2) ** decimal.Decimal(pos)
                if value >= bit_value:
                    value -= bit_value
                    current_byte += 2**bit_no
            result.append(current_byte)
        return result

    def get_bytes(self):
        return [self.exponent_byte]+self.mantissa_bytes+[self.mantissa_sign]

    def print_values(self):
        print "Float value was: %s" % self.value
        print "\texponent......: dez.: %s hex: $%02x" % (self.exponent,self.exponent)
        print "\texponent byte.: dez.: %s hex: $%02x" % (
            self.exponent_byte,self.exponent_byte
        )
        print "\tmantissa value: dez.: %s" % (self.mantissa)
        print "\tmantissa bytes: dez.: %s hex: %s" % (
            repr(self.mantissa_bytes),
            ", ".join(["$%02x" % i for i in self.mantissa_bytes])
        )
        print "\tmatissa-sign..: hex: $%02x" % self.mantissa_sign
        bytes = self.get_bytes()
        print "\tbinary........: hex: %s" % (
            ", ".join(["$%02x" % i for i in bytes])
        )
        print "\texponent |            mantissa             | mantissa-sign"
        print "\t" + " ".join(
            ['{0:08b}'.format(i) for i in bytes]
        )
        print

    def __repr__(self):
        return "<BinaryFloatingPoint %f: %s>" % (
            self.value, ", ".join(["$%02x" % i for i in self.get_bytes()])
        )


fp = FloatingPoint(54)
print fp
fp.print_values()

FloatingPoint(-54).print_values()
FloatingPoint(5.5).print_values()
FloatingPoint(-5.5).print_values()
FloatingPoint(0).print_values()
FloatingPoint(11879546).print_values()
FloatingPoint(10.14**38).print_values()
FloatingPoint(10.14**-38).print_values()
Ausgabe ist dann:
<BinaryFloatingPoint 54.000000: $86, $d8, $00, $00, $00, $00>
Float value was: 54
exponent......: dez.: 6 hex: $06
exponent byte.: dez.: 134 hex: $86
mantissa value: dez.: 0.84375
mantissa bytes: dez.: [216, 0, 0, 0] hex: $d8, $00, $00, $00
matissa-sign..: hex: $00
binary........: hex: $86, $d8, $00, $00, $00, $00
exponent | mantissa | mantissa-sign
10000110 11011000 00000000 00000000 00000000 00000000

Float value was: -54
exponent......: dez.: 6 hex: $06
exponent byte.: dez.: 134 hex: $86
mantissa value: dez.: -0.84375
mantissa bytes: dez.: [216, 0, 0, 0] hex: $d8, $00, $00, $00
matissa-sign..: hex: $ff
binary........: hex: $86, $d8, $00, $00, $00, $ff
exponent | mantissa | mantissa-sign
10000110 11011000 00000000 00000000 00000000 11111111

Float value was: 5.5
exponent......: dez.: 3 hex: $03
exponent byte.: dez.: 131 hex: $83
mantissa value: dez.: 0.6875
mantissa bytes: dez.: [176, 0, 0, 0] hex: $b0, $00, $00, $00
matissa-sign..: hex: $00
binary........: hex: $83, $b0, $00, $00, $00, $00
exponent | mantissa | mantissa-sign
10000011 10110000 00000000 00000000 00000000 00000000

Float value was: -5.5
exponent......: dez.: 3 hex: $03
exponent byte.: dez.: 131 hex: $83
mantissa value: dez.: -0.6875
mantissa bytes: dez.: [176, 0, 0, 0] hex: $b0, $00, $00, $00
matissa-sign..: hex: $ff
binary........: hex: $83, $b0, $00, $00, $00, $ff
exponent | mantissa | mantissa-sign
10000011 10110000 00000000 00000000 00000000 11111111

Float value was: 0
exponent......: dez.: 0 hex: $00
exponent byte.: dez.: 128 hex: $80
mantissa value: dez.: 0.0
mantissa bytes: dez.: [0, 0, 0, 0] hex: $00, $00, $00, $00
matissa-sign..: hex: $00
binary........: hex: $80, $00, $00, $00, $00, $00
exponent | mantissa | mantissa-sign
10000000 00000000 00000000 00000000 00000000 00000000

Float value was: 11879546
exponent......: dez.: 24 hex: $18
exponent byte.: dez.: 152 hex: $98
mantissa value: dez.: 0.708076119423
mantissa bytes: dez.: [180, 162, 30, 64] hex: $b4, $a2, $1e, $40
matissa-sign..: hex: $00
binary........: hex: $98, $b4, $a2, $1e, $40, $00
exponent | mantissa | mantissa-sign
10011000 10110100 10100010 00011110 01000000 00000000

Float value was: 169606421016759270908588940533105164288
exponent......: dez.: 127 hex: $7f
exponent byte.: dez.: 255 hex: $ff
mantissa value: dez.: 0.996856948842
mantissa bytes: dez.: [254, 152, 128, 138] hex: $fe, $98, $80, $8a
matissa-sign..: hex: $00
binary........: hex: $ff, $fe, $98, $80, $8a, $00
exponent | mantissa | mantissa-sign
11111111 11111110 10011000 10000000 10001010 00000000

Float value was: 5.8960031937775952846575658526371605536051129075884808536027556193767507219429130357164845760358320471417048480589073733426630496978759765625E-39
exponent......: dez.: -126 hex: $-7e
exponent byte.: dez.: 2 hex: $02
mantissa value: dez.: 0.501576480538
mantissa bytes: dez.: [128, 50, 212, 30] hex: $80, $32, $d4, $1e
matissa-sign..: hex: $00
binary........: hex: $02, $80, $32, $d4, $1e, $00
exponent | mantissa | mantissa-sign
00000010 10000000 00110010 11010100 00011110 00000000
Wenn das alles so stimmt, unterscheidet es sich doch vom C64 Basic, so wie es bei http://www.c64-wiki.com/index.php/Float ... arithmetic steht.
Denn das "mantissa sign" wird als erstes Bit direkt in der Mantissa gespeichert.


EDIT: Achja, die Benutzung von Decimal erscheint mir hier egal. Zumindest sehe ich keine anderen Werte, wenn ich normale floats nehme.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

So, hab nun mal meine Daten mit den aus BASIC09 (meine Emulierte Version) verglichen:

Getestet habe ich mit diesen Werten: 0, 1, 2, 126, 127, 128, 129, 130, 253, 254, 255

Übereinstimmung der Werte habe ich bei: 1, 2, 126, 127, 128, 130, 254
Unterschiedliche Werte bei: 0, 129, 253, 255

Kompletter Debug Ausgabe:

Code: Alles auswählen

    Float value was: 0
       exponent......: dez.: 0 hex: $00
       exponent byte.: dez.: 128 hex: $80
       mantissa value: dez.: 0.0
       mantissa bytes: dez.: [0, 0, 0, 0] hex: $00, $00, $00, $00
       matissa-sign..: hex: $00
       binary........: hex: $80, $00, $00, $00, $00, $00
       exponent |            mantissa             | mantissa-sign
       10000000 00000000 00000000 00000000 00000000 00000000

    Memory dump from $004f to $0054:
       $004f: $00 (dez: 0)      | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
       $0050: $00 (dez: 0)      | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
       $0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
       $0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
       $0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
       $0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
    *** ERROR:
    in RAM...: $00, $00, $00, $00, $00, $00
    Reference: $80, $00, $00, $00, $00, $00

    -------------------------------------------------------------------------------

    Float value was: 1
       exponent......: dez.: 1 hex: $01
       exponent byte.: dez.: 129 hex: $81
       mantissa value: dez.: 0.5
       mantissa bytes: dez.: [128, 0, 0, 0] hex: $80, $00, $00, $00
       matissa-sign..: hex: $00
       binary........: hex: $81, $80, $00, $00, $00, $00
       exponent |            mantissa             | mantissa-sign
       10000001 10000000 00000000 00000000 00000000 00000000

    Memory dump from $004f to $0054:
       $004f: $81 (dez: 129)    | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
       $0050: $80 (dez: 128)    | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
       $0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
       $0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
       $0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
       $0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
    *** OK

    -------------------------------------------------------------------------------

    Float value was: 2
       exponent......: dez.: 2 hex: $02
       exponent byte.: dez.: 130 hex: $82
       mantissa value: dez.: 0.5
       mantissa bytes: dez.: [128, 0, 0, 0] hex: $80, $00, $00, $00
       matissa-sign..: hex: $00
       binary........: hex: $82, $80, $00, $00, $00, $00
       exponent |            mantissa             | mantissa-sign
       10000010 10000000 00000000 00000000 00000000 00000000

    Memory dump from $004f to $0054:
       $004f: $82 (dez: 130)    | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
       $0050: $80 (dez: 128)    | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
       $0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
       $0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
       $0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
       $0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
    *** OK

    -------------------------------------------------------------------------------


    ...

    Float value was: 126
       exponent......: dez.: 7 hex: $07
       exponent byte.: dez.: 135 hex: $87
       mantissa value: dez.: 0.984375
       mantissa bytes: dez.: [252, 0, 0, 0] hex: $fc, $00, $00, $00
       matissa-sign..: hex: $00
       binary........: hex: $87, $fc, $00, $00, $00, $00
       exponent |            mantissa             | mantissa-sign
       10000111 11111100 00000000 00000000 00000000 00000000

    Memory dump from $004f to $0054:
       $004f: $87 (dez: 135)    | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
       $0050: $fc (dez: 252)    | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
       $0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
       $0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
       $0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
       $0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
    *** OK

    -------------------------------------------------------------------------------

    Float value was: 127
       exponent......: dez.: 7 hex: $07
       exponent byte.: dez.: 135 hex: $87
       mantissa value: dez.: 0.9921875
       mantissa bytes: dez.: [254, 0, 0, 0] hex: $fe, $00, $00, $00
       matissa-sign..: hex: $00
       binary........: hex: $87, $fe, $00, $00, $00, $00
       exponent |            mantissa             | mantissa-sign
       10000111 11111110 00000000 00000000 00000000 00000000

    Memory dump from $004f to $0054:
       $004f: $87 (dez: 135)    | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
       $0050: $fe (dez: 254)    | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
       $0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
       $0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
       $0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
       $0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
    *** OK

    -------------------------------------------------------------------------------

    Float value was: 128
       exponent......: dez.: 8 hex: $08
       exponent byte.: dez.: 136 hex: $88
       mantissa value: dez.: 0.5
       mantissa bytes: dez.: [128, 0, 0, 0] hex: $80, $00, $00, $00
       matissa-sign..: hex: $00
       binary........: hex: $88, $80, $00, $00, $00, $00
       exponent |            mantissa             | mantissa-sign
       10001000 10000000 00000000 00000000 00000000 00000000

    Memory dump from $004f to $0054:
       $004f: $88 (dez: 136)    | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
       $0050: $80 (dez: 128)    | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
       $0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
       $0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
       $0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
       $0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
    *** OK

    -------------------------------------------------------------------------------

    Float value was: 129
       exponent......: dez.: 8 hex: $08
       exponent byte.: dez.: 136 hex: $88
       mantissa value: dez.: 0.50390625
       mantissa bytes: dez.: [128, 128, 0, 0] hex: $80, $80, $00, $00
       matissa-sign..: hex: $00
       binary........: hex: $88, $80, $80, $00, $00, $00
       exponent |            mantissa             | mantissa-sign
       10001000 10000000 10000000 00000000 00000000 00000000

    Memory dump from $004f to $0054:
       $004f: $88 (dez: 136)    | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
       $0050: $81 (dez: 129)    | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
       $0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
       $0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
       $0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
       $0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
    *** ERROR:
    in RAM...: $88, $81, $00, $00, $00, $00
    Reference: $88, $80, $80, $00, $00, $00

    -------------------------------------------------------------------------------

    Float value was: 130
       exponent......: dez.: 8 hex: $08
       exponent byte.: dez.: 136 hex: $88
       mantissa value: dez.: 0.5078125
       mantissa bytes: dez.: [130, 0, 0, 0] hex: $82, $00, $00, $00
       matissa-sign..: hex: $00
       binary........: hex: $88, $82, $00, $00, $00, $00
       exponent |            mantissa             | mantissa-sign
       10001000 10000010 00000000 00000000 00000000 00000000

    Memory dump from $004f to $0054:
       $004f: $88 (dez: 136)    | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
       $0050: $82 (dez: 130)    | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
       $0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
       $0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
       $0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
       $0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
    *** OK

    -------------------------------------------------------------------------------


    ...

    Float value was: 253
       exponent......: dez.: 8 hex: $08
       exponent byte.: dez.: 136 hex: $88
       mantissa value: dez.: 0.98828125
       mantissa bytes: dez.: [252, 128, 0, 0] hex: $fc, $80, $00, $00
       matissa-sign..: hex: $00
       binary........: hex: $88, $fc, $80, $00, $00, $00
       exponent |            mantissa             | mantissa-sign
       10001000 11111100 10000000 00000000 00000000 00000000

    Memory dump from $004f to $0054:
       $004f: $88 (dez: 136)    | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
       $0050: $fd (dez: 253)    | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
       $0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
       $0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
       $0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
       $0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
    *** ERROR:
    in RAM...: $88, $fd, $00, $00, $00, $00
    Reference: $88, $fc, $80, $00, $00, $00

    -------------------------------------------------------------------------------

    Float value was: 254
       exponent......: dez.: 8 hex: $08
       exponent byte.: dez.: 136 hex: $88
       mantissa value: dez.: 0.9921875
       mantissa bytes: dez.: [254, 0, 0, 0] hex: $fe, $00, $00, $00
       matissa-sign..: hex: $00
       binary........: hex: $88, $fe, $00, $00, $00, $00
       exponent |            mantissa             | mantissa-sign
       10001000 11111110 00000000 00000000 00000000 00000000

    Memory dump from $004f to $0054:
       $004f: $88 (dez: 136)    | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
       $0050: $fe (dez: 254)    | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
       $0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
       $0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
       $0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
       $0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
    *** OK

    -------------------------------------------------------------------------------

    Float value was: 255
       exponent......: dez.: 8 hex: $08
       exponent byte.: dez.: 136 hex: $88
       mantissa value: dez.: 0.99609375
       mantissa bytes: dez.: [254, 128, 0, 0] hex: $fe, $80, $00, $00
       matissa-sign..: hex: $00
       binary........: hex: $88, $fe, $80, $00, $00, $00
       exponent |            mantissa             | mantissa-sign
       10001000 11111110 10000000 00000000 00000000 00000000

    Memory dump from $004f to $0054:
       $004f: $88 (dez: 136)    | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
       $0050: $ff (dez: 255)    | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
       $0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
       $0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
       $0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
       $0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
    *** ERROR:
    in RAM...: $88, $ff, $00, $00, $00, $00
    Reference: $88, $fe, $80, $00, $00, $00

    -------------------------------------------------------------------------------

    OK: [1, 2, 126, 127, 128, 130, 254]
    Failed: [0, 129, 253, 255]


Nun ist halt die Frage, sind meine Referenz Werte falsch oder kommt ein Bug in meiner Emulation zum tragen?
Mal sehen, ob ich ein BASIC Programm zusammen bekomme, die das klären kann.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Noch mal: Besorg Dir doch erst einmal Referenzwerte vom Original oder einem Emulator der nachweislich funktioniert. Und vielleicht nicht nur ganze Zahlen, sondern auch Dezimalbrüche.

Beim C64/CBM BASIC, was ja eigentlich ein Microsoft BASIC ist, gibt es zwei Formate: Einmal eins mit 6 Byte wo ein ganzes Byte für das Vorzeichen ver(sch)wendet wird, und eins mit 5 Bytes wo das Vorzeichen mit in der Mantisse gespeichert ist. Das 5 Byte-Format wird im Speicher verwendet, also da wo die BASIC-Variablen abgelegt werden, und das 6 Byte-Format ist das womit die Rechenroutinen arbeiten.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:@jens: Noch mal: Besorg Dir doch erst einmal Referenzwerte vom Original oder einem Emulator der nachweislich funktioniert. Und vielleicht nicht nur ganze Zahlen, sondern auch Dezimalbrüche.
Du hast recht. Werde ich machen.
Wie ich allerdings Dezimalbrüche in meinem Unittest der Virtuellen Maschine einfügen kann, weiß ich noch nicht wirklich.
Könnte versuchen ganze zahlen über den ACCU in FPA0 und FPA1 zu laden und dann halt eine Division an werfen.

Ich stelle allerdings so langsam die Frage, ob ich damit überhaupt die Bugs in meinem Emulator finden werde :?
Aber auf jeden Fall lerne ich dadurch eine ganze Menge. :P
BlackJack hat geschrieben:Beim C64/CBM BASIC, was ja eigentlich ein Microsoft BASIC ist, gibt es zwei Formate: Einmal eins mit 6 Byte wo ein ganzes Byte für das Vorzeichen ver(sch)wendet wird, und eins mit 5 Bytes wo das Vorzeichen mit in der Mantisse gespeichert ist. Das 5 Byte-Format wird im Speicher verwendet, also da wo die BASIC-Variablen abgelegt werden, und das 6 Byte-Format ist das womit die Rechenroutinen arbeiten.
BASIC09 ist auch von Microsoft. Ich denke es wird dort genauso gemacht.
Das Beispiel bei http://www.c64-wiki.com/index.php/Float ... on_example ist wohl die 5-Byte in Speicher Variante. Ich setzte mich allerdings gerade mit der 6-Bytes im FPA auseinander ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Letztendlich schreibst Du wenn Du daraus Unit-Tests machen willst, keine für Deinen Emulator sondern für die FP-Routinen im ROM. Der Prozessor hat ja keine FP-Befehle die man direkt testen könnte. Oder anders: Wenn die ganzen Maschinenbefehle korrekt funktionieren, dann müssen auch die FP-Routinen funktionieren.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@jens:
Weil Du mehrfach auf die C64-Seite verwiesen hast - dort ist der Exponent um eins veringert und die Mantisse entsprechend größer (1 <= Mantisse < 2) als in Deiner Berechnung. Was Du brauchst, ist eine Blaupause für die genaue Bitbelegung (Wofür steht welches Bit?) und die gültigen Wertebereiche. Mit genügend Dumps vom Original bzw. einem funktionierenden Emulator lässt sich das vllt. über reverse engineering rausfinden, falls es da keine formale Beschreibung für gibt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:@jens: Letztendlich schreibst Du wenn Du daraus Unit-Tests machen willst, keine für Deinen Emulator sondern für die FP-Routinen im ROM. Der Prozessor hat ja keine FP-Befehle die man direkt testen könnte. Oder anders: Wenn die ganzen Maschinenbefehle korrekt funktionieren, dann müssen auch die FP-Routinen funktionieren.
Genau das ist ja das Problem. Irgendwelche Machinen Befehle funktionieren halt noch nicht richtig. Denn ein "PRINT 6" liefert als Ausgabe nicht "6" sondern: " .0/////909 " :?

Das suchen der fehlerhaften Instruktion, durch abklappern der trace Ausgaben ist echt schwierig.
Der Fehler liegt irgendwo beim Evalusieren von Zahlen und in BASIC werden alle Zahlen in Gleitkomma-Zahlen konvertiert. Also dachte ich mir, schaue ich den Teil mir erstmal an.

Auch wenn meine Vergleiche nicht 100% sich gleichen, gehe ich davon aus, das der Weg Zahl -> Float ok ist.

Hab auch angefangen ein BASIC Programm zu schreiben um in einem funktionierenden Emulator das ganze Anzeigen zu lassen: https://github.com/jedie/PyDragon32/blo ... t_FPA0.bas

Das Skript ist einfach: Packe eine zahl auf den CPU Accumulator D und rufe die Routine im ROM auf, die D nach FPA0 einfügt. Dann zeige ich den Speicherinhalt von FPA0 an.

Funktioniert allerdings noch nicht. Das kommt raus:

Bild

Als Referenz gibt es das geniale Buch "Inside the Dragon" Gibt es als PDF hier: http://archive.worldofdragon.org/archiv ... Dragon.pdf
Dort ab Seite 230 geht es los... Darauf stützt sich meine Implementierung.



Btw. eine funktionierende 6809 Emulation im Brower findet sich auch hier: http://www.asm80.com
Dort kann man oben auf "SBC6809" klicken und landet im Basic ROM, mit dem ich auch teste: https://github.com/jedie/DragonPy/tree/ ... Simple6809
Vom ROM gibt es auch eine sehr gut dokumentierte Version: https://github.com/jedie/DragonPy/blob/ ... BasROM.LST

Beim asm80.com Emulator kann man auch direkt mit der CPU Spielen:
* Auf "New file" rechts klicken
* Datei mit Endung ".a09" anlegen
* In Assembler schreiben
* rechts auf "Emulator" klicken

Der Assembler code wird in Machinen Code gewandelt und man kann ihn Ausführen.
Bsp:

Code: Alles auswählen

        CLRB        ; B is always 0
        TFR B,U     ; clear U
loop:
        TFR U,A     ; for next NEGA
        TFR B,CC    ; clear CC
        NEGA
        LEAU 1,U    ; inc U
        JMP loop
wird zu:

Code: Alles auswählen

0000   5F                     CLRB   ; B is always 0
0001   1F 93                  TFR   B,U   ; clear U
0003                LOOP:     
0003   1F 38                  TFR   U,A   ; for next NEGA
0005   1F 9A                  TFR   B,CC   ; clear CC
0007   40                     NEGA   
0008   33 41                  LEAU   1,U   ; inc U
000A   0E 03                  JMP   loop   
Wenn man den Step-by-Step ausführt kann man sehen was NEGA macht.


Sowas würde ich irgendwann auch gern in meinem Emulator machen...
Aber erstmal müßen die Bugs raus :(

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich kann DragonPy auch über die schulter sehen. Hab einen HTML trace eingebaut.
z.B. sieht der Teil der Evaluierung von dez. 54 in FPA0 so aus: https://www.jensdiemer.de/media/dragonp ... 51212.html

Dabei fehlt die Initialisierung des BASIC Interpreter.

Debug Ausgabe des Tests ist:

Code: Alles auswählen

Float value was: 54
	exponent......: dez.: 6 hex: $06
	exponent byte.: dez.: 134 hex: $86
	mantissa value: dez.: 0.84375
	mantissa bytes: dez.: [216, 0, 0, 0] hex: $d8, $00, $00, $00
	matissa-sign..: hex: $00
	binary........: hex: $86, $d8, $00, $00, $00, $00
	exponent |            mantissa             | mantissa-sign
	10000110 11011000 00000000 00000000 00000000 00000000

Memory dump from $004f to $0054:
	$004f: $86 (dez: 134)    | $4f: *PV FLOATING POINT ACCUMULATOR #0 FPA0 EXPONENT
	$0050: $d8 (dez: 216)    | $50: *PV FLOAT.ACCU #0 FPA0 MANTISSA MS  Most Significant Byte
	$0051: $00 (dez: 0)      | $51: *PV FLOAT.ACCU #0 FPA0 MANTISSA NMS Next Most Significant Byte
	$0052: $00 (dez: 0)      | $52: *PV FLOAT.ACCU #0 FPA0 MANTISSA NLS Next Least Significant Byte
	$0053: $00 (dez: 0)      | $53: *PV FLOAT.ACCU #0 FPA0 MANTISSA LS  Least Significant Byte
	$0054: $00 (dez: 0)      | $54: *PV FLOATING POINT ACCUMULATOR #0 FPA0 SIGN
*** OK

Beim komplettes Initialisieren von BASIC + den Befehl "PRINT 6" und Ausgabe erhält man eine 4MB große trace HTML Datei: https://www.jensdiemer.de/media/dragonp ... 51708.html
Irgendwo darin läuft was falsch. Aber den Fehler in den 20.300 Op-Code Aufrufen zu finden ist echt viel Arbeit.
Dabei ist der Trace noch kürzer als in echt, weil ich eingestellt habe, das es nur 1KB RAM gibt. Ansonsten würde halt die Initialisierung die ganzen 32KB durch gehen, um festzulegen, wie viel RAM "eingebaut" sind ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Bei dem BASIC-Programm würde ich den FPA0 noch im Maschinenprogrammteil irgendwo anders hin kopieren lassen. Denn zumindest beim C64 wird der FPA ja vom laufenden BASIC-Programm aus benutzt, das heisst Du änderst den Wert vielleicht schon durch das auslesen weil dem PEEK()-Befehl ja eine Zahl übergeben wird, die der BASIC-Interpreter von ASCII nach Zahl umwandeln muss. CBM-BASIC kennt da nur Dezimalzahlen und benutzt dafür den FPA. Folglich kann man den FPA selbst mit PEEK nicht auslesen ohne ihn zu verändern, zumindest nicht wenn man als Argument eine literale Zahl angibt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:@jens: Bei dem BASIC-Programm würde ich den FPA0 noch im Maschinenprogrammteil irgendwo anders hin kopieren lassen. Denn zumindest beim C64 wird der FPA ja vom laufenden BASIC-Programm aus benutzt, das heisst Du änderst den Wert vielleicht schon durch das auslesen weil dem PEEK()-Befehl ja eine Zahl übergeben wird, die der BASIC-Interpreter von ASCII nach Zahl umwandeln muss. CBM-BASIC kennt da nur Dezimalzahlen und benutzt dafür den FPA. Folglich kann man den FPA selbst mit PEEK nicht auslesen ohne ihn zu verändern, zumindest nicht wenn man als Argument eine literale Zahl angibt.
Du hast, wie so oft recht :lol:

Ich hab den Code auch geändert: https://gist.github.com/jedie/22dba94f5b7534f946f9

Dennoch kommt nichts richtiges dabei raus:
Bild

Vielleicht sollte ich es mal mit FPA1 statt FPA0 probieren... Evtl. ist der Aufruf der Machine Code programms mit "EXEC LA" aber evtl. schon schuld?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Da scheint es ein Muster zu geben, dass sich der Wert immer bei einer 2er-Potenz ändert. :-)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:@jens: Da scheint es ein Muster zu geben, dass sich der Wert immer bei einer 2er-Potenz ändert. :-)
Stimmt... Deswegen bin ich mal weiter gegangen und siehe da:

Bild

Immerhin, scheint das "mantissa sign" sich richtig zu verhalten...

Ich hab auch mal mit meine Code folgendes gemacht:

Code: Alles auswählen

    for i in xrange(0x100):
        fp = BASIC09FloatingPoint(i)
        print "%3s -> %s" % (
            i,
            " ".join(["$%02x" % i for i in fp.get_bytes()])
        )
Nur ein Ausschnitt:
120 -> $87 $f0 $00 $00 $00 $00
121 -> $87 $f2 $00 $00 $00 $00
122 -> $87 $f4 $00 $00 $00 $00
123 -> $87 $f6 $00 $00 $00 $00
124 -> $87 $f8 $00 $00 $00 $00
125 -> $87 $fa $00 $00 $00 $00
126 -> $87 $fc $00 $00 $00 $00
127 -> $87 $fe $00 $00 $00 $00
128 -> $88 $80 $00 $00 $00 $00
129 -> $88 $80 $80 $00 $00 $00
130 -> $88 $82 $00 $00 $00 $00
131 -> $88 $82 $80 $00 $00 $00
132 -> $88 $84 $00 $00 $00 $00
133 -> $88 $84 $80 $00 $00 $00
134 -> $88 $86 $00 $00 $00 $00

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

jens hat geschrieben:So, hab nun mal meine Daten mit den aus BASIC09 (meine Emulierte Version) verglichen:

Getestet habe ich mit diesen Werten: 0, 1, 2, 126, 127, 128, 129, 130, 253, 254, 255

Übereinstimmung der Werte habe ich bei: 1, 2, 126, 127, 128, 130, 254
Unterschiedliche Werte bei: 0, 129, 253, 255
Ich hab mal Spaßeshalber einen kompletten Durchlauf von 0-255 gemacht:
OK: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254]

Failed: [0, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255]

Interessantes Muster :P

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

So, nach den letzten Bugfixes [1,2] geht es nun für Glanzzahlen von $0-$ffff:

[1] https://github.com/jedie/DragonPy/commi ... 3e885ed002
[2] https://github.com/jedie/DragonPy/commi ... d5f4a60d28

Nun würde ich gern mal sehen, was passiert, wenn ich versuche Divisionen vor zu nehmen... Ich denke mal ich werde auf unterschiedliche Rundungsfehler stoßen...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

Ich habe mal spasseshalber Konvertierungsfunktionen für die beiden C64-BASIC Fliesskommazahlenformate geschrieben:

Code: Alles auswählen

from __future__ import print_function
import math
from struct import Struct

MFLOAT_STRUCT = Struct('>BI')
FAC_FLOAT_STRUCT = Struct('>BIb')
assert MFLOAT_STRUCT.size == 5 and FAC_FLOAT_STRUCT.size == 6


def _float2cbm_float(value):
    sign = 0
    mantissa, exponent = math.frexp(value)
    
    if mantissa or exponent:
        exponent += 128
        if not 0 <= exponent <= 255:
            raise OverflowError

        if mantissa < 0:
            mantissa = -mantissa
            sign = 1

        mantissa = mantissa * 2**32

    return exponent, int(mantissa + 0.5), sign


def float2cbm_mfloat(value):
    exponent, mantissa, sign = _float2cbm_float(value)
    return MFLOAT_STRUCT.pack(exponent, (mantissa & 0x7fffffff) | (sign << 31))


def float2cbm_fac_float(value):
    exponent, mantissa, sign = _float2cbm_float(value)
    return FAC_FLOAT_STRUCT.pack(exponent, mantissa, -1 if sign else 0)


def cbm_float2float(value):
    if len(value) == 5:
        exponent, mantissa = MFLOAT_STRUCT.unpack(value)
        sign = mantissa >> 31
        if exponent:
            mantissa |= 0x80000000
    elif len(value) == 6:
        exponent, mantissa, sign = FAC_FLOAT_STRUCT.unpack(value)
    else:
        raise ValueError('wrong byte length for a cbm float')

    result = mantissa * 2.0**(exponent - 128 - 32)
    return -result if sign else result


def main():
    for value in [
        0, 0.5, 0.1, -1, -0.25, 100, -1000, -42.23, 3.141592653589793, 10e200
    ]:
        mfloat = float2cbm_mfloat(value)
        fac_float = float2cbm_fac_float(value)
        py_float_a = cbm_float2float(mfloat)
        py_float_b = cbm_float2float(fac_float)
        print(
            mfloat.encode('hex'),
            fac_float.encode('hex'),
            value,
            py_float_a,
            py_float_a == py_float_b,
            value - py_float_a
        )


if __name__ == '__main__':
    main()
Antworten