Hi all,
. Sometimes some friends here ask me where is the
ASM file ? Here we have the
converters from
real4 to string and from
string to real4,
without using the slow BCD method or ...
. Well, in this post i give
ConverterDD.inc <<<< replaced by ConverterDF.inc which contain the
ASM ConvertString4D procedure,
the
ASM ConvertFloat4DD procedure, constants
and macros.
. ConvertFloat converts to a string with a «dd ?» behind the address
. ConvertFloat4DD convert a dword real4 variable
into a string. In the text file CnvRealDD.txt
i try to explain something about that.
. I give also the ASM ConvertString4D and
a text file Converter4.txt
where i explain something about that.
. TestCnvDD12.exe shows conversions of some values
. TestCnvDD13.exe shows timing table of
some converters
. Please, could you run TestCnvDD13.exe
and show the results here ?
Thanks
Rui Loureiro
EDIT: please
replace $DECIMALPLACES_REAL4 equ 7
by
$DECIMALPLACES_REAL4 equ
6 and ADD this:
$OR_TRUNCATE$ equ 0C00h EDIT: i replaced ConvertFloat4DD by
ConvertFloat4DF----------------------------------------------------
Converting from real4 to string using FPU
----------------------------------------------------
Well, because there are people that want to try to write
his own converter or they are trying to learn,
i will try to remember some basic concepts.
This is just to answer some questions like
«why you do this ?», «why you do that ?» ...
RuiLoureiro
---------------------------------------------------------
A. Writing a real number in scientific notation
---------------------------------------------------------
A1. A number X= 1345.6789 written in scientific notation stands for:
X= 1.3456789 * 10^3
(move the point 3 places right to get the original and remove the power)
A number Y= 0.0013456789 written in scientific notation stands for:
Y= 1.3456789 * 10^-3
(move the point 3 places left to get the original and remove the power)
A2. Any number, in scientific notation, is written like this:
d.xxxxxxx * 10^n (it may start with a sign)
if n is positive: move the decimal point n places forward
if n is negative: move the decimal point n places backward
after moving we remove the power factor
to move backward, first add '0' behind (0000000000000d.xxxxxxx* 10^n)
dont forget this: any number inside FPU is in scientific notation
or floating point notation.
It has one integer digit plus dp decimal digits
The first digit is the first significant digit
and the others also, they dont run away from there.
------------------------------------------------------
B. scientific notation and dp decimal places
-------------------------------------------------------
Whenever we write a real number in scientific notation
we write it with:
. 1 integer digit ( ip not null) and
. dp decimal paces
Given a number X= 12345.67890123456789
we have:
X= 1.2345 6789 0123 4567 89 * 10^4
ip=1 and dp=18
Now, if we remove the last 11 digits we get
X= 1.2345 678 * 10^4
ip=1 and dp=7
Now, if we add 2 digits we get
X= 1.2345 678 90 * 10^4
ip=1 and dp=9
Note that, in scientific notation, ip is a contant 1
and dp is an important variable.
--------------------------------------------------------------------
C. Converting a real number X to an integer number I
with id integer digits
--------------------------------------------------------------------
Given a number X= 12345.67890123456789
we have:
X= 1.2345 6789 0123 4567 89 * 10^4
ip=1 and dp=18
. If we want an integer I with id digits
we want id= dp+1 =>
dp= id-1
. If we want an integer with id= 8 digits
it is the same to say we want dp=7
So we want this:
Y= 1.2345 678 * 10^4
(after '.' we write 7 digits)
dont forget this: any number inside FPU is in scientific notation
It has one integer digit plus dp decimal digits
-----------------------------------------------------------------------------
D. Converting any real X number written in scientific notation
into Y with exactly dp decimal places (Y not equal X)
-----------------------------------------------------------------------------
Given
X= d.xxxxxxx * 10^exponent (any integer exponent)
we need:
1) to remove (10^exponent) factor
which we do multiplying by
10^-exponent
to get
Xi= d.xxxxxxx * 10^exponent * 10^-exponent
( 10^exponent * 10^-exponent= 1)
= d.xxxxxxx
2) now, we have not the power factor
(and Xi is not equal X but has the same digits)
So, we need to move the point dp places right.
So, we need to multiply Y by 10^dp (dp is a positive integer)
Y= d.xxxxxxx * 10^dp (scientific notation with dp decimal places)
which is ( Y = dxxxxxxx. )
Point 1) and 2) means that we need to multiply X by
10^-exponent * 10^dp = 10^(dp-exponent)
If we do
--------------------------------
expscale = dp - exponent
--------------------------------
the rule is: we need to multiply X by 10^expscale
Y = X * 10^expscale
where
expscale = dp - exponent
This number Y has the same digits as X and (dp+1) total integer digits
For instance,
. if we want 7 decimal places, dp=7 we have
expscale = 7-exponent
Y = X * 10^expscale
and it has 8 integer digits.
. if we want 18 decimal places, dp=18 we have
expscale = 18-exponent
Y = X * 10^expscale
and it has 19 integer digits.
note: given a X number inside FPU we suppose we may do this
operations without error. If error, we cannot.
-----------------------------------------------------------------------------
E. Converting any real X number written in scientific notation
into an integer I with exactly id integer digits
------------------------------------------------------------------------------
As we have seen before
dp = id -1
and ------------------------
Y = X * 10^expscale where expscale = dp - exponent
------------------------
So, we need only to convert Y to an integer I.
FPU instruction fistp do this for us, we dont need to do nothing more.
In both following examples we want dp= 5 decimal places
EXAMPLE 1
--------------
X = 1.235 * 10^3 and dp=5 => expscale=5-3=2
Y = 1.235 * 10^3 * 10^2
= 1.235 * 10^5
= 123500.0
fistp should give I=123500
total number of digits should be = 6
exponent should be = 3 => print 4 integer digits
" 1 point
" (6-4) decimal digits
EXAMPLE 2
--------------
X = 1.235 * 10^-2 and dp=5 => expscale=5+2=7
Y = 1.235 * 10^-2 * 10^7
= 1.235 * 10^5
= 123500.0
fistp should give I=123500
total number of digits should be = 6
exponent should be = -2
so |exponent|= 2
|exponent|-1 = 1
=> print '0.'
print 1 '0'
" 4 decimal digits (to get 5 dp)
note: To get the exponent, we calculate log10(X) and return the
integer part or characteristic. See it below.
-----------------------------------
F. FPU and integer numbers
-----------------------------------
note: log is log10 (base 10), log2(X) (base 2)
Whenever we load an integer number from memory to FPU st(0) it is
converted to a real10 format
fild dword ptr Integer32 ; loads the Integer32 to a real10 format st(0)
Whenever we want to store into memory the value st(0), it is rounded to an integer32
fistp dword ptr Integer32 ; converts the real10 format st(0) to Integer32
frndint rounds st(0) to a corresponding integer and stores it in the same st(0)
note that we cannot load an integer from a register
To do it we should do this, for instance
push eax or
fild dword ptr [esp] mov Integer32, eax
add esp, 4 fild Integer32
-----------------------------------------
G. logarithm of base 10 function
dp, id and exponent
-----------------------------------------
note: to get the exponent we get the characteristic of log10(X)
which we get truncating the log10(X) (not rounding)
-------------------------------------------
CASE 1: the exponent is positive or null
-------------------------------------------
example 1
number X dp id log10(X) exponent
---------- ---- ---- ---------------- -----------
1.0 0 1 -> log(10^0) = 0 0
10.0 1 2 -> log(10^1) = 1 1
100.0 2 3 -> log(10^2) = 2 2
1000.0 3 4 -> log(10^3) = 3 3
100000... n n+1 -> log(10^n) = n n
---------------------------------------------------------------------------
rule 1: the number of integer digits is exponent+1 (=dp+1)
---------------------------------------------------------------------------
example 2
number X dp id log10(X) exponent
---------- ---- ---- --------------------------- -------------
1200.0 3 4 -> log(1.2*10^3) = 3.079181246047625 3
1999.9 3 4 -> log(1.999999*10^3) = 3.301029778516686 3
9999.9 3 4 -> log(9.999999*10^3) = 3.99999995657055 3
10000.0 4 5 -> log(1.0 10^4) = 4.0 4
..............................................................................
9999.9999 3 4 -> log(9.999999999999999*10^3) = 4.0 4 <---- except
If we truncate the log10(X) to an integer the exponent is = dp
So, the number X has
exponent+1 = dp+1 =id integer digits.
But there is a case where the exponent is 4 and dp=3.
Or
exponent = dp +1
that case is X=9.9999999999999 * 10^dp
but when we round it to integer we get this: round (9999.9)= 10000 = 10^4
and we have exponent= 4,
So,
-----------------------------------------------------------------
the number of integer digits is exponent+1 (rule 1)
-----------------------------------------------------------------
note: when we start the problem, we say we want to get dp decimal places
and the number of integer digits is id= dp+1.
At the end, we may get id-1.
But there, we dont use dp but the exponent
and
-----------------------------------
the rule 1: id = exponent+1
-----------------------------------
and because we know the total number of digits
------------------------------------
the decimal places is total-id
------------------------------------
------------------------------------
CASE 2: the exponent is negative
------------------------------------
id = number of digits in the buffer after converting
X to an integer with dp=7
exponent = characteristic of ( log10(X) ) from FPU
example 1
number X log10(X) id exponent
---------- ------------------- ---- ------------
0.1 -> log(10^-1) = -1 8 0 <--> exponent=exponent -1
0.01 -> log(10^-2) = -2 8 -2
0.001 -> log(10^-3) = -3 7 -2 <--> exponent=exponent -1 (id=dp)
0.0001 -> log(10^-4) = -4 8 -4
0.00001 -> log(10^-5) = -5 8 -5
0.000001 -> log(10^-6) = -6 8 -6
0.0000001 -> log(10^-7) = -7 7 -6 <--> exponent=exponent -1 (id=dp)
0.00000001 -> log(10^-8) = -8 8 -8
0.000000001 -> log(10^-9) = -9 8 -9
After correcting the exponent, (because id=dp or exponent=0)
|exponent|-1 is the number of '0' we should set after '0.'
For exponent = -4 => |exponent|-1 = 3 => 0. 000 1
example 2
corrected
number X log10(X) id exponent exponent
---------- ------------------- ---- ----------- ----------
0.2 -> log(2 10^-1) = 0 8 0 -1
0.02 -> log(2 10^-2) = -1 7 -1 -2
0.002 -> log(2 10^-3) = -2 7 -2 -3
0.0002 -> log(2 10^-4) = -3 7 -3 -4
0.00002 -> log(2 10^-5) = -4 7 -4 -5
0.000002 -> log(2 10^-6) = -5 7 -5 -6
0.0000002 -> log(2 10^-7) = -6 7 -6 -7
0.00000002 -> log(2 10^-8) = -7 7 -7 -8
0.000000002 -> log(2 10^-9) = -8 7 -8 -9
example 3
corrected
number X log10(X) id exponent exponent
---------- ------------------- ---- ----------- ----------
0.d -> log(5 10^-1) = 0 8 0 -1
0.0d -> log(5 10^-2) = -1 7 -1 -2
0.00d -> log(5 10^-3) = -2 7 -2 -3
0.000d -> log(5 10^-4) = -3 7 -3 -4
0.0000d -> log(5 10^-5) = -4 7 -4 -5
0.00000d -> log(5 10^-6) = -5 7 -5 -6
0.000000d -> log(5 10^-7) = -6 7 -6 -7
0.0000000d -> log(5 10^-8) = -7 7 -7 -8
0.00000000d -> log(5 10^-9) = -8 7 -8 -9
«d» is 2, 3, 4, 5, 6, 7, 8 or 9
example 4
corrected
number X log10(X) id exponent exponent
---------- ------------------- ---- ----------- ----------
0.9 -> log(9 10^-1) = 0 8 0 -1
0.09 -> log(9 10^-2) = -1 7 -1 -2
0.009 -> log(9 10^-3) = -2 7 -2 -3
0.0009 -> log(9 10^-4) = -3 7 -3 -4
0.00009 -> log(9 10^-5) = -4 7 -4 -5
0.000009 -> log(9 10^-6) = -5 7 -5 -6
0.0000009 -> log(9 10^-7) = -6 7 -6 -7
0.00000009 -> log(9 10^-8) = -7 7 -7 -8
0.000000009 -> log(9 10^-9) = -8 7 -8 -9
After correcting the exponent, (because id=dp or exponent=0)
|exponent|-1 is the number of '0' we should set after '0.'
For exponent = -4 => |exponent|-1 = 3 => 0. 000 1
--------------------------------------------------------------------------------------
rule 2: the number of zeroes after '0.' is |exponent|-1 (corrected exponent)
---------------------------------------------------------------------------------------
note 1: we correct expscale only if the logarithm is negative and exponent =0.
So, in this case, we get dp digits only and not dp+1.
In all other cases exponent is not corrected before getting the integer.
0.001 = 10^-3 the exponent is =-2 => expscale=7+2=9
10^-3 * 10^9 = 10^6=1000000 instead of 10^7
EDIT:
ConverterDD was replaced by
ConverterDF (some bugs/fails was corrected: test for -0.0 and PowerTable: 1 is 1.0 and 10 is 10.0)
Now we may use
ConvertFloat4DF or
ConvertReal4DF