Re: ZXSimulator
Posted: Tue Jun 11, 2024 2:10 am
Starting my first crack at introducing floating point into ZXSimulator. Main concern is speed and of course always conscious of space as well. Digital 'C' SE uses a library with function calls to implement floating point, and its data structures takes up 48 bits per number (an array of 3 ints). So that will be both slow and take lots of memory.
My idea is to do the old bookkeeping method of assuming the last two digits are the decimal place, i.e. 1.00 is represented as 1 00 or 100, etc. That only gives 2 digits after the decimal point, but at least it allows for some precision floating point. Using 32 bits (a long) this will make the number range approximately 24 bits (high number of 21 million instead of 16 million for 24 bits). Initial bonus is that it won't slow down adding and subtracting and so things like FOR loops or simple GOTO loops will continue to run just as fast.
Multiplication and division will be harder. I think initially I will implement them like this:
Multiplication:
a * b / 100
Division:
a * 100 / b
This has some major limitations in that the size of numbers to multiply or divide becomes rather small. Plus, simple math like this, breaks, i.e. 250,000 / 1 overflows because its representation would be 25000000 (i.e. for 250000.00), and when multiplied by 100 it becomes 2.5 billion which is past the half mark of 4 billion a 32 bit integer can store. Multiplication is even worse, as numbers as small as 500 can't be multiplied together, i.e. 500 x 500 overflows because its representation is 50000 x 50000 which again equals 2.5 billion.
I could fix multiplication...for variable a and b to be multiplied, I could do this:
a1 = a / 100;
a2 = a % 100;
b1 = b / 100;
b2 = b % 100;
(a1*b1*100) + ((a2*b2)/100) + (a2*b1) + (a1*b2);
But that is a lot of computation for a simple operation (and I don't know how to fix division similarly). In the end, I will implement multiplication and division with Digital 'C' SE's floating point library calls and then copy its result back into a 32-bit long value. This will guarantee I only overflow when I'e hit the absolute max.
So with the initial change to 32 bit and the simple implementation of multiply and divide above, there are really only two places I need to change code to get this to work: 1) in the PRINT routine, to make sure I normalize (divide by 100) when printing out (and decide when to print decimal and when to ignore it), and 2) any place I either parse or input a number, where I need to make sure to multiply by 100 and ensure it's an integer.
Those are my next steps.
Edit: I guess I could speed up the convoluted multiplication by doing this, though that is still a lot of processing:
a2 = a % 100;
b1 = b / 100;
b2 = b % 100;
a*b1 + ((a2*b2)/100) + (a2*b1);
My idea is to do the old bookkeeping method of assuming the last two digits are the decimal place, i.e. 1.00 is represented as 1 00 or 100, etc. That only gives 2 digits after the decimal point, but at least it allows for some precision floating point. Using 32 bits (a long) this will make the number range approximately 24 bits (high number of 21 million instead of 16 million for 24 bits). Initial bonus is that it won't slow down adding and subtracting and so things like FOR loops or simple GOTO loops will continue to run just as fast.
Multiplication and division will be harder. I think initially I will implement them like this:
Multiplication:
a * b / 100
Division:
a * 100 / b
This has some major limitations in that the size of numbers to multiply or divide becomes rather small. Plus, simple math like this, breaks, i.e. 250,000 / 1 overflows because its representation would be 25000000 (i.e. for 250000.00), and when multiplied by 100 it becomes 2.5 billion which is past the half mark of 4 billion a 32 bit integer can store. Multiplication is even worse, as numbers as small as 500 can't be multiplied together, i.e. 500 x 500 overflows because its representation is 50000 x 50000 which again equals 2.5 billion.
I could fix multiplication...for variable a and b to be multiplied, I could do this:
a1 = a / 100;
a2 = a % 100;
b1 = b / 100;
b2 = b % 100;
(a1*b1*100) + ((a2*b2)/100) + (a2*b1) + (a1*b2);
But that is a lot of computation for a simple operation (and I don't know how to fix division similarly). In the end, I will implement multiplication and division with Digital 'C' SE's floating point library calls and then copy its result back into a 32-bit long value. This will guarantee I only overflow when I'e hit the absolute max.
So with the initial change to 32 bit and the simple implementation of multiply and divide above, there are really only two places I need to change code to get this to work: 1) in the PRINT routine, to make sure I normalize (divide by 100) when printing out (and decide when to print decimal and when to ignore it), and 2) any place I either parse or input a number, where I need to make sure to multiply by 100 and ensure it's an integer.
Those are my next steps.
Edit: I guess I could speed up the convoluted multiplication by doing this, though that is still a lot of processing:
a2 = a % 100;
b1 = b / 100;
b2 = b % 100;
a*b1 + ((a2*b2)/100) + (a2*b1);