The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: jj2007 on July 05, 2009, 11:45:44 PM

Title: Basic-style Str$
Post by: jj2007 on July 05, 2009, 11:45:44 PM
As an alternative to Masm32 FloatToStr and crt_sprintf, the attached FloatStr.asm provides an easy way to print numbers using the print Str$(123) syntax.

Reasons to use it (at your own risk, of course):
- faster than FloatToStr (*2) and crt_sprintf (*14)
- flexible (integer, reals, immediate reals, registers can be freely mixed)
- full REAL10 precision
- free :bg

Reasons not to use it:
- not tested for all possible combinations

Testing float$
PI      3.14159265358979323846 (there are more digits...)
Str$    3.141592653589793238
crt     3.14159265358979310

mov eax, 333: eax/3 =   111
Forced real:     123.0000000
Forced integer:  333/4 = 83

Str$ performs simple calculation (up to 5 arguments,
CAUTION: sequential, i.e. 2*5+2*5=(10+2)*5):
See the result of a calculation involving 5 different data types
(imm32, immReal, reg32, real10, reg8):
esi=52, ebx=23:
120/2.5+esi+MyReal10+bl = 123.4567890123456789


Timings on Celeron M:
291     cycles for Str$
605     cycles for FloatToStr
4317    cycles for crt_sprintf
99      cycles for dwtoa (int32 only)


To use it, extract all files to a folder of your choice and run InstallFloatStr.bat

Note this is the replacement for the slightly inexact float$ shown here (http://www.masm32.com/board/index.php?topic=9756.0).

EDIT: Qwords do not print directly, but edx::eax can be used:

.data
MyQword dq 1234567890123456789
.code
mov eax, dword ptr MyQword
mov edx, dword ptr MyQword[4]
print Str$("\nA qword: %i", edx::eax)


QuoteA qword: 1234567890123456789

Edit(2+3+4): New version with increased precision attached.
Edit(5): Chr$(eax) example added
Edit(6): MovVal example added:    MovVal MyReal10, chr$("-123456.789e-33")
Edit(7): Bugfix - used to return 0.0 if ecx was zero on proc entry

[attachment deleted by admin]
Title: Re: Basic-style Str$
Post by: dedndave on July 07, 2009, 03:08:26 AM
cool Jochen
looks like you worked hard on this one
i thought you might have something that displayed 64-bit integers up your sleeve - lol
i noticed that your value for Pi has 21 usable (i.e. correct) digits
i only got 20 - i may need to re-visit my conversion method
EDIT
oh - lol - that is a string - ya got me
Title: Re: Basic-style Str$
Post by: jj2007 on July 14, 2009, 08:46:20 AM
Quote from: dedndave on July 07, 2009, 03:08:26 AM
i noticed that your value for Pi has 21 usable (i.e. correct) digits
i only got 20 - i may need to re-visit my conversion method
EDIT
oh - lol - that is a string - ya got me

Yes, that was a string - but with the attached new version, you do get 19 digits, see below.
For getting the full 19, use Str$("%Jf", MyReal10).
Note that the inherent FPU precision implies that the 19th digit is not guaranteed to be exact. Use uppercase I for 18 digits.

        1x234567890123456789 digits precision
PI      3.14159265358979323846... (there are many more digits...)
Str$    3.141592653589793238      (jj2007)
crt     3.14159265358979310       (CRT printf or sprintf)
FloatTo 3.141593                  (Masm32 lib FloatToStr)

Log2(e) 1.44269504088896340736...
Str$    1.442695040888963407
crt     1.44269504088896340
FloatTo 1.442695

Lg2(10) 3.3219280948873623480...
Str$    3.321928094887362348
crt     3.32192809488736220
FloatTo 3.321928

Lg10(2) 0.30102999566398119521...
Str$    0.3010299956639811952
crt     0.30102999566398120
FloatTo 0.30103

Lge(2)  0.69314718055994530942...
Str$    0.6931471805599453094
crt     0.69314718055994529
FloatTo 0.6931472


mov eax, 333: eax/3 =   111
A qword: 1234567890123456789    (using edx::eax)
Forced real:     123.0000000
Forced integer:  333/4 = 83

Str$ performs simple calculations
(up to 5 arguments, CAUTION: sequential, i.e. 2*5+2*5=(10+2)*5):
See the result of a calculation involving 5 different data types
(imm32, immReal, reg32, real10, reg8, esi=52, ebx=23):

120/2.5+esi+MyReal10+bl = 123.4567890123456789

Syntax: print Str$("\nThe value is %9f", MyVar1*MyVar2/bx+12.34+esi)
Qualifiers: \n newline, \t tab
%i = int32; %f = real, 7 digits (default)
%3f = real, 3 digits; %Af = real, 10 digits; %Jf = real, 19 digits


EDIT: To avoid confusion, latest version from now on always attached to first post.
Title: Re: Basic-style Str$
Post by: dedndave on July 14, 2009, 11:58:24 AM
i ran the FPU value for Pi through my eval.exe program:
+3.14159265358979323851280895940618620443274267017841339111328125  FPU representation of Pi
+3.1415926535897932384626..........................                                              actual value of Pi
20 usable decimal digits (just barely - lol)
Title: Re: Basic-style Str$
Post by: jj2007 on July 14, 2009, 12:42:34 PM
Quote from: dedndave on July 14, 2009, 11:58:24 AM
i ran the FPU value for Pi through my eval.exe program:
+3.14159265358979323851280895940618620443274267017841339111328125  FPU representation of Pi
+3.1415926535897932384626..........................                                              actual value of Pi
20 usable decimal digits (just barely - lol)

Str$ yields 3.1415926535897932384626... and that is what you also get as valid digits. The 5 is already incorrect, so it's 19 digits :bg

Raymond's Simply FPU says REAL10 has 19.5 digits precision. No way to go beyond that... unless we embark for REAL16.
Title: Re: Basic-style Str$
Post by: dedndave on July 14, 2009, 01:24:27 PM
it is considered a usable digit, as the "4626" rounds up to "5000"
it is coincidental, however - it applies to this specific value - not all values
if you have to represent Pi with 20 decimal digits, what would the last digit be? (answer: 5)
the value shown is the precise evaluation of the FPU's FLDPI binary representation of Pi
(3.14159265358979323851280895940618620443274267017841339111328125)
if Ray returns a different value, he is cheating somehow - lol
i would think the FLDPI has the geometrically closest value to Pi that may be represented in extended float
QuoteStr$ yields 3.1415926535897932384626
that is 23 decimal digits - i think you are looking at a value that was defined as an ascii string
QuoteRaymond's Simply FPU says REAL10 has 19.5 digits precision. No way to go beyond that
that contradicts the 23 digit value
Title: Re: Basic-style Str$
Post by: jj2007 on July 14, 2009, 01:46:32 PM
Quote from: dedndave on July 14, 2009, 01:24:27 PM
it is considered a usable digit, as the "4626" rounds up to "5000"

Sure?

12.34690 rounded to the nearest tenth is 12.3 (http://www.321know.com/est-dec-round.htm)

Quote
QuoteStr$ yields 3.1415926535897932384626
that is 23 decimal digits

I meant the ones up to 3238 - that's why I put them in blue.
Title: Re: Basic-style Str$
Post by: dedndave on July 14, 2009, 01:54:23 PM
yes - i am sure
1.4626 rounded to the nearest tenth is 1.5
Title: Re: Basic-style Str$
Post by: dedndave on July 14, 2009, 01:55:54 PM
3.141592653589793238295968524909085317631252110004425048828125     next lower extended real value

3.14159265358979323851280895940618620443274267017841339111328125  FPU Pi

3.1415926535897932387296493939032870912342332303524017333984375    next higher extended real value

notice how they all end with 5 - that is because ALL binary fractions end with 5 when represented in decimal
binary    decimal

.1        .5
.01       .25
.001      .125

and so on
Title: Re: Basic-style Str$
Post by: jj2007 on July 14, 2009, 02:04:46 PM
Quote from: dedndave on July 14, 2009, 01:55:54 PM
3.141592653589793238295968524909085317631252110004425048828125     next lower extended real value
3.14159265358979323851280895940618620443274267017841339111328125  FPU Pi
3.1415926535897932387296493939032870912342332303524017333984375    next higher extended real value

I see what you mean, Dave. The problem is that we are demanding something from the FPU that it cannot perform: Getting the 46. The nearest to the 46 that is representable with 64 digits is the 51 - but one tick of the LSB is -22/+21, so even the 5 is no longer a valid digit, if not by accident. Olly cuts off as 32380, which is slightly incorrect in that the 0 should not be shown. Crt sprintf behaves even worse...
Title: Re: Basic-style Str$
Post by: dedndave on July 14, 2009, 02:09:38 PM
that's right
here is the problem:
if you round 3.14159265358979323851 to 19 digits, it is 3.141592653589793239 - you induce an error by rounding
Title: Re: Basic-style Str$
Post by: dedndave on July 14, 2009, 03:05:44 PM
well - that is half the problem - lol
before we ever got our hands on the binary value from the FPU,
the guys at intel had to round the correct value of Pi to the nearest value representable by their numbering system
THEN, we come along and round it again to convert it to a decimal string

3.1415926535897932384626... actual value of Pi
3.1415926535897932385128... closest extended real binary value
3.141592653589793239        our best interpretation of that binary value
3.141592653589793238        actual value of Pi rounded to 19 digits

i suppose "our best interpretation" might actually be the 20 digit value 3.1415926535897932385
but, that is stretching the 191/2 digit resolution of the 64-bit binary
i don't think it is practical to always render 20 digits
you might do something like this:
if the leading digit is 1-4, render 20 digits
otherwise, render 19 digits
(the 1-4 is a guess - we would have to find the correct value to use in place of the 4)
to complicate issues a bit, we could examine a few leading digits to determine the switch-over point
typically, when they refer to "1/2 digit", they mean a leading 1
many digital volt-meters display 31/2 or 41/2 digits
most of them mean a leading 1
a few use a leading 3 - they display 5 digits up to 3.9999, then switch to 4 digits at 4.000

EDIT
examining the 2 leading digits would be a practical way to determine the switch point
Title: Re: Basic-style Str$
Post by: jj2007 on July 14, 2009, 09:06:03 PM
Quote from: dedndave on July 14, 2009, 03:05:44 PM

a few use a leading 3 - they display 5 digits up to 3.9999, then switch to 4 digits at 4.000


Like this?

include \masm32\include\masm32rt.inc
include \masm32\macros\FloatStr.asm

.code
start:
print Str$("%8f\n", 3.99999999)
print Str$("%9f\n", 3.99999999)
exit
end start


4.0000000
3.99999999
Title: Re: Basic-style Str$
Post by: dedndave on July 14, 2009, 09:27:20 PM
you have the right idea, Jochen
now all you need is the right cross-over point
you should examine with care whether or not digits are "usable"

3.141592653589793238 295968524909085317631252110004425048828125     next lower extended real value
3.141592653589793238 51280895940618620443274267017841339111328125  FPU Pi
3.141592653589793238 7296493939032870912342332303524017333984375    next higher extended real value

at this point, we no longer take into consideration what the original intended value was meant to be (Pi in this case)
the value you are converting into a string has a precise evaluation
in this case, that would be 3.14159265358979323851, as you have no intention of displaying more than 20 digits
rounding it to 19 digits would be 3.141592653589793239
anything we display from 3.1415926535897932381 to 3.1415926535897932389 is closer to the precise value than rounding it to 19 digits
that one is coincidental, because the 20th digit is a 5
if the 20th digit were a 3, rounding the value to 19 digits would round downward (that 3 would be truncated)
notice that the 20th digit could be a 2, and it would still be closer to the precise value than if it were rounded to 19 digits
in fact, we could display 20 digits with anything from 2 to 5 at the end and it would be closer to the precise value than if it were rounded off
the point is, "usable digits" are not neccessarily the correct value
they are usable, so long as they get us closer to the precise value than if they were rounded off


Title: Re: Basic-style Str$
Post by: dedndave on July 14, 2009, 09:38:57 PM
i am guessing that if the first 2 signifigant digits of a value are 10 through 36, 20 usable digits are available
if they are 37 through 99, only 19 digits are usable
that guess is based on 2 x (2^64) = 36,893,488,147,419,103,232
at that value, each change of 1 to the lsb changes the the result by 2

403F_FFFFFFFF_FFFFFFFF: +36893488147419103230
4040_80000000_00000000: +36893488147419103232
4040_80000000_00000001: +36893488147419103236
4043_9FFFFFFF_FFFFFFFF: +368934881474191032288
4043_A0000000_00000000: +368934881474191032320
4043_A0000000_00000001: +368934881474191032352
4046_C7FFFFFF_FFFFFFFF: +3689348814741910322944
4046_C8000000_00000000: +3689348814741910323200
4046_C8000000_00000001: +3689348814741910323456

i added hex output to the prog - lol
maybe i shoulld do another decade or two
you can see what happens as i go above that value - the lsd changes by 4 instead of 2 in the first example
Title: Re: Basic-style Str$
Post by: jj2007 on July 14, 2009, 10:04:41 PM
Hmmm... interesting. However, I guess we are stuck with the problem that we do not know a priori what was the intended value - we get what the FPU can give us, in a 19.x digits resolution. So instead of trying to "interpret" the intentions of the number's unknown author, we should simply cut off at 19 digits. Which, by the way, seems not to be quite understood by the CRT guys - they allow higher, and therefore fake, precision than they can theoretically achieve:

1/7 with Str$, max precision:
0.1428571428571428571
same with crt_printf:
0.1428571428571429
0.14285714285714285
0.142857142857142850
0.1428571428571428500


The first crt value is correctly rounded - the others are plain wrong.

include \masm32\include\masm32rt.inc
include \masm32\macros\FloatStr.asm

.data
r7inv real8 0.0
r7 real8 7.0

.code
start:
print Str$("1/7 with Str$, max precision:\n%Jf\nsame with crt_printf:\n", 1/7)
fld1
fld r7
fdiv
fst r7inv
invoke crt_printf, chr$("%.16f"), r7inv
print chr$(13, 10)
invoke crt_printf, chr$("%.17f"), r7inv
print chr$(13, 10)
invoke crt_printf, chr$("%.18f"), r7inv
print chr$(13, 10)
invoke crt_printf, chr$("%.19f"), r7inv
getkey
exit
end start
Title: Re: Basic-style Str$
Post by: dedndave on July 14, 2009, 10:21:43 PM
you shouldn't have to know the intended value
1) get 20 digits - or 21, or even 22 if possible (that way digit #21 has not already been rounded)
2) examine the first 2 (or more) digits to determine the round-off length (4 would be great - if 3688 or less -> 20 digits)
3) round the string to that length

that method will yield
3.1415926535897932385
instead of
3.141592653589793238
or
3.141592653589793239
Title: Re: Basic-style Str$
Post by: jj2007 on July 14, 2009, 10:34:23 PM
Quote from: dedndave on July 14, 2009, 10:21:43 PM
you shouldn't have to know the intended value
1) get 20 digits - or 21, or even 22 if possible

Not possible...

Quote3.1415926535897932382959     next lower extended real value
3.1415926535897932385128  FPU Pi
3.1415926535897932387296    next higher extended real value

The 5 is digit 20, and it is not even the intended value. It just happens to be a bit (pun intended) closer to the intended 4 than 2 or 7...
Title: Re: Basic-style Str$
Post by: dedndave on July 14, 2009, 10:36:39 PM
i evaluated the value to way more than 22 digits
so, it is possible
it is a usable digit - on a value that has a 3 at the end - still usable - see previous post
or just ignore me - lol
i know you too well, my friend - you are thinking "that is going to cost xxx clock cycles" - lol
Title: Re: Basic-style Str$
Post by: jj2007 on July 14, 2009, 10:43:35 PM
Quote from: dedndave on July 14, 2009, 10:36:39 PM
i evaluated the value to way more than 22 digits
so, it is possible
it is a usable digit - on a value that has a 3 at the end - still usable - see previous post
or just ignore me - lol
i know you too well, my friend - you are thinking "that is going to cost xxx clock cycles" - lol

The engineer's rule is "if you display a digit, it should be the correct one, otherwise do not display it". CRT violates that rule.

Dave, I will ignore you for technical reasons - it's well after midnight over here. Little suggestion: Change example - 1/7 is a good one., since we know exactly the corect output.
Title: Re: Basic-style Str$
Post by: dedndave on July 14, 2009, 10:49:41 PM
QuoteThe engineer's rule is "if you display a digit, it should be the correct one, otherwise do not display it".
i am an engineer
and that isn't the rule - lol
to get the full 191/2 digits, you can do as i suggested
or just toss out the 1/2 digit
fact is, that is probably more convenient in terms of formatting text (easier to make all the columns the same width)
Title: Re: Basic-style Str$
Post by: MichaelW on July 15, 2009, 12:39:52 AM
Quote from: jj2007 on July 14, 2009, 10:43:35 PM
The engineer's rule is "if you display a digit, it should be the correct one, otherwise do not display it". CRT violates that rule.

IMO that is a reasonable rule, but the CRT does not violate it. The CRT allows you to specify the number of significant digits, and specifying more digits than the precision for the type violates the rule. One can take issue with the decision to eliminate support for 80-bit long doubles, but it's not like the technical details are some sort of secret. The decimal-digit precision for the relevant types is normally specified in float.h:

#define DBL_DIG   15        /* # of decimal digits of precision */
#define FLT_DIG   6         /* # of decimal digits of precision */
#define LDBL_DIG  DBL_DIG   /* # of decimal digits of precision */

Title: Re: Basic-style Str$
Post by: dedndave on July 15, 2009, 05:31:10 AM
19 digits IS overkill - for 98% of all applications
as i said before, i normally convert to single for display
sometimes, i display full resolution so that i may decide how many digits are meaningful
the only things that i may want to display with great accuracy and resolution are times or frequencies
after giving it more thought, 19 digits can even be misleading
that is, if much calculation has been performed
once you have made a few simple multiplications, divisions, additions, or subtractions,
the 19th digit is merely an attempt to retain more detail than needed
any trigonometry or exponentiation really makes that digit meaningless - lol
also, the constants that you load may have a slight deviation from the "intended" value, to begin with
10(Pi-3) is an example of how quickly digits may be lost
on the other hand, if i load 2 constants and multiply them, the 19th digit should be "in the right neighbourhood" - lol
Title: Re: Basic-style Str$
Post by: jj2007 on July 15, 2009, 06:15:23 AM
Quote from: MichaelW on July 15, 2009, 12:39:52 AM
Quote from: jj2007 on July 14, 2009, 10:43:35 PM
The engineer's rule is "if you display a digit, it should be the correct one, otherwise do not display it". CRT violates that rule.

IMO that is a reasonable rule, but the CRT does not violate it. The CRT allows you to specify the number of significant digits, and specifying more digits than the precision for the type violates the rule


I cannot completely disagree :bg

(sounds familiar: "this bug is by design")
Title: Re: Basic-style Str$
Post by: MichaelW on July 15, 2009, 07:05:28 AM
A maximum of 19 digits would be reasonable for an 80-bit long double. For example, in a float.h copyrighted 1987, when 80-bit long doubles were supported:

#define LDBL_DIG  19

But I agree that the repetitive approximations involved in complex calculations do tend to make the last few digits less meaningful, and I think this was at least part of the justification for removing support for 80-bit long doubles.
Title: Re: Basic-style Str$
Post by: jj2007 on July 15, 2009, 07:43:29 AM
Quote from: MichaelW on July 15, 2009, 07:05:28 AM

But I agree that the repetitive approximations involved in complex calculations do tend to make the last few digits less meaningful, and I think this was at least part of the justification for removing support for 80-bit long doubles.


It is not that bad, actually:
                        1x234567890123456789 digits precision
PI                      3.14159265358979323846...
Str$                    3.141592653589793238
Pi*333/333              3.141592653589793238
Pi+1.2345678-1.2345678  3.141592653589793238
Pi+1.2345*10/10-1.2345  3.141592653589793238


Str$ is not intelligent enough to eliminate the 333/333 - the calculations are actually being performed, apparently without losing a single digit.

EDIT: A check with Olly reveals that PI is
4000 C90FDAA2 2168C235 before the calculations and
4000 C90FDAA2 2168C234 after the calculations.
According to Dave's routine, this translates to
3.1415926535897932385128  original PI
3.1415926535897932382959  PI*333/333
They both round to the same 19-digit number, so the last digit (8) is not lost but with a slightly different set of calculations it might have become a 9. Note this is an issue only for calculating numbers, not for simply displaying an extended real.

EDIT(2): For the calculation Pi+1.2345*10/10-1.2345, the internal result is 4000 C90FDAA2 2168C232. Olly displays it as 3.1415926535897932380
Title: Re: Basic-style Str$
Post by: jj2007 on July 26, 2009, 09:01:37 PM
I added a Basic-style Chr$(). The Masm32 library version does not allow
mov eax, "A"
print chr$(eax)  ; fails


The new Chr$() is compatible with chr$ but allows to embed registers or variables into the text. Example:

QuoteMyTest proc
LOCAL Lv1:DWORD, Lv2:BYTE
  mov Lv1, "c"
  mov Lv2, "d"
  mov eax, "a"
  print Chr$(13, 10, "Chr$ accepts registers: ", eax, ", global: ", gChar0, " and local DWORD: ", Lv1, " or BYTE: ", Lv2, " variables", 13, 10, 10)

  mov ebx, "A"
  .Repeat
     print Str$(ebx)
     print Chr$(" corresponds to ", ebx, 13, 10)
       inc ebx
  .Until ebx>"J"
  ret
MyTest endp

Output:
QuoteChr$ accepts registers: a, global: b and local DWORD: c or BYTE: d variables

65 corresponds to A
66 corresponds to B
67 corresponds to C
68 corresponds to D
69 corresponds to E
70 corresponds to F
71 corresponds to G
72 corresponds to H
73 corresponds to I
74 corresponds to J

You can use al, cl, dl etc. instead of eax, ecx, edx. Variables can be any size, but only the lobyte will be used.
Attachment below the top post.
Title: Re: Basic-style Str$
Post by: dedndave on July 26, 2009, 10:28:52 PM
i like your library, my friend
although, i wrote a function for this that is as fast as i could make it - lol
as Hutch said, "it's console mode - who cares how fast it is"
the fact that you have to call an API function at all seems slow
if i wanted to make a really fast one, i suppose i would stick the char into the video buffer
Title: Re: Basic-style Str$
Post by: jj2007 on July 27, 2009, 06:23:51 AM
Quote from: dedndave on July 26, 2009, 10:28:52 PM
i like your library, my friend
although, i wrote a function for this that is as fast as i could make it - lol
as Hutch said, "it's console mode - who cares how fast it is"
the fact that you have to call an API function at all seems slow
if i wanted to make a really fast one, i suppose i would stick the char into the video buffer

Well, Chr$ is not necessarily for console output - you might as well use it for a MessageBox. I wanted a function as flexible as the BASIC equivalent, and optimised for size (but there is hardly a "speedier" version):
00401001       |.  57                      push edi
00401002       |.  BF 881B4000             mov edi, 00401B88  <<< string buffer
00401007       |.  8807                    mov [edi], al
00401009       |.  C647 01 00              mov byte ptr [edi+1], 0
0040100D       |.  8BC7                    mov eax, edi
0040100F       |.  5F                      pop edi
00401010       |.  8BD0                    mov edx, eax
00401012       |.  57                      push edi
00401013       |.  BF 881B4000             mov edi, 00401B88  <<< string buffer, the same again
00401018       |.  8807                    mov [edi], al
0040101A       |.  C647 01 00              mov byte ptr [edi+1], 0
0040101E       |.  8BC7                    mov eax, edi
00401020       |.  5F                      pop edi
00401021       |.  8BD0                    mov edx, eax
Title: Re: Basic-style Str$
Post by: jj2007 on August 14, 2009, 04:24:30 PM
Time for an update: The counterpart to Str$ is Val("123.456"). The new version, attached at the top of this thread, implements Val as MovVal dest, src. Examples:

MyPI   db   "3.141592653589793238", 0

MovVal eax, chr$("123.456")
print Str$("MbVal eax, 123.456:\t%i\n",eax)

MovVal ecx, chr$("456.789")
print Str$("MbVal ecx, 456.789:\t%i\n",ecx)
MovVal edx, chr$("123.456e7")
print Str$("MbVal edx, 123.456e7:\t%i\n\n",edx)

print "Test PI with various destination sizes:", 13, 10, 9, 9
print offset MyPI, 13, 10

MovVal MbReal10, offset MyPI ; works fine
print Str$("MbVal10:  \t%Jf\n",MbReal10)

MovVal MbReal8, offset MyPI
print Str$("MbVal8:   \t%Jf\n",MbReal8)

MovVal MbReal4, offset MyPI
print Str$("MbVal4:   \t%Jf\n\n",MbReal4)


Output:
MovVal eax, 123.456:     123
MovVal ecx, 456.789:     457
MovVal edx, 123.456e7:   1234560000

Test PI with various destination sizes:
                3.141592653589793238
MovVal10:        3.141592653589793238
MovVal8:         3.141592653589793116
MovVal4:         3.141592741012573242


As usual, timings are competitive - see MovValTimings.exe in the archive.