How does the floating point math package in BASIC work?

Hardware Hacking, Programming and Game Solutions/Cheats
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

How does the floating point math package in BASIC work?

Post by jedie »

I still try to bugfix my Emulator: viewtopic.php?f=5&t=4308&p=11316#p11316

There is a bug somewhere related with the BASIC09 "floating point math package"...

So i try to understand how it works. I find a article "Floating Point Math" by "Steven R. Broadwater" in the The Rainbow Magazine (Radio Shack Color Computer) (February 1985) -> https://archive.org/details/rainbowmagazine-1985-02

It helps a little, but hey this is hardcore stuff for me ;)

I would like to try some simple function from the math package, as descried in the article.

I used the Simple6809 ROM. There are some equal addresses:
Floating Point Accu 0 is also stored in $0050-$0053
FPA0 Exponent in $004f and FPA Sign in $0054

FPA1 stored in $005c-$0061

I found two interesting Routines in ROM:
$e777 = CONVERT THE VALUE IN ACCB INTO A FP NUMBER IN FPA0
$e778 = CONVERT THE VALUE IN ACCD INTO A FLOATING POINT NUMBER IN FPA0

So i try to store the number "6" into FPA0 via CPU accu B:
The ASCII Number 6 is $36 so i try this:

Code: Select all

0000   C6 36                  LDB   #$36   
0002   BD E7 77               JSR   $e777   
The result is:

Code: Select all

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
are this the right values?
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: How does the floating point math package in BASIC work?

Post by jedie »

Question: What floating point format is it?

Seems that is not a a standard format, isn't it? not IEEE 754-1985 or?

Seems that the float values are stored like this:

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)

or not?

EDIT: Seems that's the same "format" as the C64 used, see: http://www.c64-wiki.com/index.php/Float ... arithmetic

What i not understand: Storing the sign into one byte, seems to be "extravagance"... For the information is only one bit needed, isn't it?
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
User avatar
tormod
Posts: 416
Joined: Sat Apr 27, 2013 12:06 pm
Location: Switzerland
Contact:

Re: How does the floating point math package in BASIC work?

Post by tormod »

This is very well explained in "Inside the Dragon", section 9.3. I can recommend reading the whole book! :)
User avatar
JeeK
Posts: 67
Joined: Fri Aug 16, 2013 10:45 am
Location: Vienna, Austria
Contact:

Re: How does the floating point math package in BASIC work?

Post by JeeK »

jedie wrote:I still try to bugfix my Emulator: viewtopic.php?f=5&t=4308&p=11316#p11316
[..]
I found two interesting Routines in ROM:
$e777 = CONVERT THE VALUE IN ACCB INTO A FP NUMBER IN FPA0
$e778 = CONVERT THE VALUE IN ACCD INTO A FLOATING POINT NUMBER IN FPA0

So i try to store the number "6" into FPA0 via CPU accu B:
The ASCII Number 6 is $36 so i try this:

Code: Select all

0000   C6 36                  LDB   #$36   
0002   BD E7 77               JSR   $e777   
The result is:

Code: Select all

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
are this the right values?
Seems correct. But your assumption is wrong. Register B is taken as value (if signed integer, this will be -128 to 127) and not as a ASCII coded digit!
If I calculate the value back from the FP representation

Code: Select all

$36 = 54

Float: 
86         d8        00       00       00       00

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


(0.5+0.25+0.0625+0.03125)*2^6 = 54
This float value represents decimal 54 which is hex $36, the value you stored in register B. ;)
The dragon on my side: http://klasek.at/hc/dragon/
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: How does the floating point math package in BASIC work?

Post by jedie »

Ah! Thanks!
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: How does the floating point math package in BASIC work?

Post by jedie »

tormod wrote:This is very well explained in "Inside the Dragon", section 9.3. I can recommend reading the whole book! :)
Also thanks! I found it ;)
JeeK wrote:If I calculate the value back from the FP representation

Code: Select all

$36 = 54

Float: 
86         d8        00       00       00       00

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


(0.5+0.25+0.0625+0.03125)*2^6 = 54
Here is something wrong.
$86 is: 10000110 and not 10001010 (this is $8a)
Is $86 wrong or just the binary representation?

EDIT: Is this correct ?

Code: Select all

2^(+6)
10000110   110110000 00000000 00000000 00000000 00000000
+    4     || ||
     +2    || ||
           || |+ 0.03125
           || +- 0.0625
           |+--- 0.25
           +---- 0.5
 
(0.5+0.25+0.0625+0.03125)*2^6 = 54
Last edited by jedie on Mon Jul 07, 2014 10:25 pm, edited 1 time in total.
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: How does the floating point math package in BASIC work?

Post by jedie »

jedie wrote:What i not understand: Storing the sign into one byte, seems to be "extravagance"... For the information is only one bit needed, isn't it?
From "Inside the Dragon": It's just for speed ;)
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
User avatar
JeeK
Posts: 67
Joined: Fri Aug 16, 2013 10:45 am
Location: Vienna, Austria
Contact:

Re: How does the floating point math package in BASIC work?

Post by JeeK »

jedie wrote:
tormod wrote:This is very well explained in "Inside the Dragon", section 9.3. I can recommend reading the whole book! :)
Also thanks! I found it ;)
JeeK wrote:If I calculate the value back from the FP representation

Code: Select all

$36 = 54

Float: 
86         d8        00       00       00       00

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


(0.5+0.25+0.0625+0.03125)*2^6 = 54
Here is something wrong.
$86 is: 10000110 and not 10001010 (this is $8a)
Is $86 wrong or just the binary representation?
This was a typo by me. For sure, $86 is 10000110, $80 + 4 + 2 ;)

As a side note:
Most FP schemes uses an offset by $80 "biased" representation:

Code: Select all

Value     Exp.    Value
$00         -      0 (special marker) 
$01      -127      mantissa * 2^(-127)
$80         0      mantissa * 1
$FF      +127      mantissa * 2^127
This "biased rep." has the advantage that 2 values could be easily compared byte-wise like strings without the need for subtraction of both values ...
The dragon on my side: http://klasek.at/hc/dragon/
User avatar
JeeK
Posts: 67
Joined: Fri Aug 16, 2013 10:45 am
Location: Vienna, Austria
Contact:

Re: How does the floating point math package in BASIC work?

Post by JeeK »

jedie wrote:
jedie wrote:What i not understand: Storing the sign into one byte, seems to be "extravagance"... For the information is only one bit needed, isn't it?
From "Inside the Dragon": It's just for speed ;)
Basic interpreters (like MS-derived) use two representations: optimized
  • for speed in calculations (FP accumulators) the sign is separate, the leading bit of the normalized is in place
  • for space, e.g. storing values in variables or variable arrays: the sign is encoded in the first leading bit of the mantissa which is always 1, because the mantissa is normalized (starts always with 0.1xxxxx).
The dragon on my side: http://klasek.at/hc/dragon/
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: How does the floating point math package in BASIC work?

Post by jedie »

I have created a Python class for representing a BASIC-Float:

Code: Select all

#!/usr/bin/env python

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()])
        )


FloatingPoint(54).print_values()
FloatingPoint(-54).print_values()
FloatingPoint(5.5).print_values()
FloatingPoint(-5.5).print_values()
FloatingPoint(0).print_values()
FloatingPoint(10.14**38).print_values()
FloatingPoint(10.14**-38).print_values()
with syntax highlighting -> https://gist.github.com/jedie/94f8d310bb88fdb0d188



Example output is:

Code: Select all

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: 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


Don't know if this all is correct.
JeeK wrote:for space, e.g. storing values in variables or variable arrays: the sign is encoded in the first leading bit of the mantissa which is always 1, because the mantissa is normalized (starts always with 0.1xxxxx).
Then it looks simmilar to the C64 example here: http://www.c64-wiki.com/index.php/Float ... on_example

But here the Exponent is calculated with: 152 - 129 = 23
But Inside Dragon says an page 232: 128 must be subtracted.
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
Post Reply