Page 1 of 2
ZX Floating point to Decimal code in BASIC
Posted: Mon Jul 21, 2014 10:47 am
by David G
I wrote this 10 years ago, not sure how accurate it is. But it seems to work. Comments/corrections are welcomed.
David G
Code: Select all
Sub FloatToDec (ZxString$, DecNumber#)
Dim FirstByte As Double
Dim ZxDigits As Double
Dim SecondByte As Double
Dim t As Double
Dim Xdigits As Double
Dim ZxSign As Double
Dim figure As Double
zero$ = String$(5, Chr$(0))
If ZxString$ = zero$ Then DecNumber# = 0: Exit Sub
'get sign from second byte
SecondByte = Asc(Mid(ZxString$, 2, 1))
ZxSign = SecondByte And 128
'Adjust second byte after getting sign
Mid(ZxString$, 2, 1) = Chr$(SecondByte Or 128)
'drop trailing bytes that equal 0
'result in x$
For f = 5 To 2 Step -1
If Asc(Mid(ZxString$, f, 1)) Then
Exit For
End If
Next f
x$ = Mid(ZxString$, 2, f - 1)
'get # of binary digits needed from first byte
FirstByte = Asc(Mid(ZxString$, 1, 1))
ZxDigits = FirstByte - 128
'drop trailing bits that equal 0
DecNumber# = Asc(Right(x$, 1))
For f = 8 To 1 Step -1
If DecNumber# And 1 Then Exit For
Let DecNumber# = DecNumber# / 2
Next f
'f = number of significant bits
'get # of binary digits in base number
Xdigits = (Len(x$) - 1) * 8 + f
'convert string to base number
t = 0 'counter for powers of figure (256)
figure = 2 ^ f
For f = (Len(x$) - 1) To 1 Step -1
DecNumber# = DecNumber# + Asc(Mid(x$, f, 1)) * figure * (256 ^ t)
t = t + 1
Next f
'based on exponent, modify number to correct number
'of binary digits
Let DecNumber# = DecNumber# * 2 ^ (ZxDigits - Xdigits)
If ZxSign Then Let DecNumber# = -DecNumber#
End Sub
Re: ZX Floating point to Decimal code in BASIC
Posted: Mon Jul 21, 2014 11:01 pm
by XavSnap
Hi,
Thanks David.
In VB81 Xur, the revers function (Decimal to ZXfp), seem to be bugged using "1.5", "1,2" values !
Can your have a look to this code : (Vb81 XuR/ZxToken:ModZXUtil.bas)
(I had to type VAL('"1.2") to get the right value!)
Code: Select all
' ZX81 floating point number.
Type Zx81_Long
Exp As Integer ' - Exponent
man As String ' - Mantissa
End Type
Function dbl2zx81(Num As Single) As Zx81_Long
'On Error Resume Next
' * Converts a double to an inline-basic-style ZX81 floating point number.
' *
' * IN: num - Number to convert (dbl)
' * OUT: &exp - Exponent (integer)
' * OUT: &man - Mantissa (char)
' *
Dim IntNum As Double
Dim tmpint1 As Double
Dim tmpint2 As Double
Dim TmpVal As String
Dim Expon As Double
' /* Special case for zero */
If Num = 0 Then
dbl2zx81.Exp = 0#
dbl2zx81.man = 0#
Exit Function
End If
' /* If negative work with the absolute value */
If Num < 0 Then Num = -Num
dbl2zx81.Exp = Int(Log(Num) / Log(2))
If dbl2zx81.Exp < -129 Or dbl2zx81.Exp > 126 Then Exit Function
IntNum = ((Num / (2# ^ (dbl2zx81.Exp + Expon#))) * 2147483648#)
' 65536=&h10000
' 32767=&h7FFF
tmpint2 = IntNum - (Fix(IntNum / 65536#) * 65536#) - 28
tmpint1 = (IntNum / 65536#) And 32767#
If tmpint2 < 0 Then tmpint2 = 0
TmpVal = Hex16(UnsignedToLong(tmpint1)) & Hex16(UnsignedToLong(tmpint2))
dbl2zx81.man = TmpVal
dbl2zx81.Exp = dbl2zx81.Exp + 129#
Exit Function
Dbl_ERR:
Disp_Err 11, Str(Num)
End Function
Re: ZX Floating point to Decimal code in BASIC
Posted: Tue Jul 22, 2014 6:53 pm
by olofsen
The "28" should perhaps be "128" to clear the sign bit for positive numbers?
Code: Select all
tmpint2 = IntNum - (Fix(IntNum / 65536#) * 65536#) - 128
Re: ZX Floating point to Decimal code in BASIC
Posted: Tue Jul 22, 2014 7:14 pm
by XavSnap
tmpint2 = IntNum - (Fix(IntNum / 65536#) * 65536#) - 28
tmpint2 = IntNum - (Fix(IntNum / 65536#) * 65536#) - 128
True, somethings wrong...
I don't know if i's due to a sign remover, or a "FIX" leek how had to correct the value using the "28" value !
In Zxfp, there isn't any sign, and all values are positive.
May be the VB integer leek, how use his own sign tag !
If the FIX value is translated in Integer, we lost 1 bit in the "FIX" return value...
Re: ZX Floating point to Decimal code in BASIC
Posted: Tue Jul 22, 2014 7:29 pm
by olofsen
May be we can compare intermediate results: for num=12345, intnum=3236167680, tmpint1=0 and tmpint2=49380 or 0xc0e4 but it should be 0x40e4?
Re: ZX Floating point to Decimal code in BASIC
Posted: Sun Jul 27, 2014 6:07 am
by David G
For comparison, here is the same BASIC routine converted to C++
known issues:
* since it doesn't calculate the FP conversion in the exact same way as ZX81 Basic, it rounds differently.
* I haven't tested or implemented E+00 notation for extremely large or extremely small numbers
Code: Select all
#include <math.h> // or <tgmath.h>
double FloatToDec(BYTE* ZxFP)
{ // input is the 5 bytes that comprise the floating point number
BYTE x[6];
double DecNumber = 0;
int f;
int t;
BYTE Xdigits;
int ZxDigits;
BOOL ZxSign;
double figure;
if(memcmp(ZxFP,"\000\000\000\000\000",5) == 0)
{
return 0;
}
//'get sign from second byte
ZxSign = ZxFP[1] & 128;
//'Adjust second byte after getting sign
BYTE dd = ZxFP[1];
ZxFP[1] = dd | 128;
//drop trailing BYTES that equal 0
//'result in x$
for( f = 4; f >= 1; f--)
{
if(ZxFP[f] != 0)
break;
}
int len_x = f;
memcpy(x,ZxFP+1, len_x); //x[len_x]=0;
//'get # of binary digits needed from first byte
BYTE FirstByte =ZxFP[0];
ZxDigits = FirstByte - 128;
// drop trailing BITS that equal 0
BYTE bb = x[len_x - 1];
for(f = 8; f >= 1 ; f--)
{
if(bb & 1)
break;
bb = bb >> 1;
}
DecNumber = bb;
//f now contains the number of significant bits
//'get # of binary digits in base number
Xdigits = ((unsigned char)len_x - 1) * 8 + (unsigned char)f;
//'convert string to base number
t = 0; // 'counter for powers of figure (256)
figure = pow((double)2, f);
for(f = len_x - 1; f >= 1; f--)
{
DecNumber = DecNumber + x[f-1] * figure * pow((double)256,t);
t = t + 1;
}
//'based on exponent, modify number to correct number
//'of digits
DecNumber = DecNumber * pow((double)2,ZxDigits - Xdigits);
if (ZxSign)
DecNumber = -DecNumber;
return DecNumber;
}
For display, I use sprintf "%f", and truncate any '0' characters after the decimal point ('.')
Re: ZX Floating point to Decimal code in BASIC
Posted: Sun Jul 27, 2014 6:23 am
by David G
For ZX81 floating point, the sign is in the 2nd value byte as shown in the original "ZX81 BASIC Programming" book.
Chapter 27 - Organization of memory
Re: ZX Floating point to Decimal code in BASIC
Posted: Sun Jul 27, 2014 7:28 am
by David G
In VB81 Xur, the revers function (Decimal to ZXfp), seem to be bugged using "1.5", "1,2" values !
Can your have a look to this code : (Vb81 XuR/ZxToken:ModZXUtil.bas)
(I had to type VAL('"1.2") to get the right value!)
It appears to work correctly. I ran the posted code in Visual Basic and a sample number was correctly converted.
I downloaded ModZXUtil.bas from
http://zx81.vb81.free.fr/download/VB81_RES.zip, however if does not appear have the function "Decimal to ZXfp" (dbl2zx81) in it. In the code above I don't see "1.5" or "1,2".
Re: ZX Floating point to Decimal code in BASIC
Posted: Sun Jul 27, 2014 1:06 pm
by PokeMon
For calculating/converting floating points in programs, this is a good source:
http://www.users.waitrose.com/~thunor/m ... ter17.html
Re: ZX Floating point to Decimal code in BASIC
Posted: Sat Apr 07, 2018 7:26 am
by XavSnap
Hi all,
I tried to use the David Gonzales's codes in an update of SnaList (from Chris Cowley) on Spectrum Tap/TZX.
A new C++ routine on the Floating Point conversion from _SAM_ & Hlide: (Fr lang)
http://forum.system-cfg.com/viewtopic.p ... b0e23879dd
Code: Select all
//*******************************************************************
// Spectrum/ZX81 Floating point decoder From _SAM_ et hlide
//*******************************************************************
//IN: 5 Bytes : 1 EXP + 4 Mantissa (sign on the secound byte)
//OUT: DOUBLE
double decode(unsigned char fp[5]) {
double mantisse;
if(fp[0]==0) {
double t = fp[1]*65536 + fp[3]*256 + fp[2];
if(fp[1]&128) t -= 256*65536;
return t;
}
mantisse = (((fp[4]/256.0 + fp[3])/256.0 + fp[2])/256.0 + fp[1])/128.0;
if(mantisse < 1) mantisse += 1; // nombre positif
else mantisse = -mantisse; // nombre negatif
return mantisse*pow(2, fp[0]-129);
}
[EDITED 2018-04-24]