Pages: [1] 2
|
 |
|
Author
|
Topic: Basic-style Str$ (Read 24546 times)
|
jj2007
|
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  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.batNote this is the replacement for the slightly inexact float$ shown here. 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) A 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]
|
|
« Last Edit: August 16, 2009, 11:00:03 PM by jj2007 »
|
Logged
|
|
|
|
dedndave
|
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
|
|
|
Logged
|
|
|
|
jj2007
|
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.
|
|
« Last Edit: July 17, 2009, 06:46:21 AM by jj2007 »
|
Logged
|
|
|
|
dedndave
|
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)
|
|
|
Logged
|
|
|
|
jj2007
|
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.141592653589793 2384626... and that is what you also get as valid digits. The 5 is already incorrect, so it's 19 digits  Raymond's Simply FPU says REAL10 has 19.5 digits precision. No way to go beyond that... unless we embark for REAL16.
|
|
|
Logged
|
|
|
|
dedndave
|
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 Str$ yields 3.1415926535897932384626 that is 23 decimal digits - i think you are looking at a value that was defined as an ascii string Raymond's Simply FPU says REAL10 has 19.5 digits precision. No way to go beyond that that contradicts the 23 digit value
|
|
|
Logged
|
|
|
|
|
dedndave
|
yes - i am sure 1.4626 rounded to the nearest tenth is 1.5
|
|
|
Logged
|
|
|
|
dedndave
|
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
|
|
|
Logged
|
|
|
|
jj2007
|
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 3238 0, which is slightly incorrect in that the 0 should not be shown. Crt sprintf behaves even worse...
|
|
|
Logged
|
|
|
|
dedndave
|
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
|
|
|
Logged
|
|
|
|
dedndave
|
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
|
|
« Last Edit: July 14, 2009, 05:16:06 PM by dedndave »
|
Logged
|
|
|
|
jj2007
|
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
|
|
|
Logged
|
|
|
|
dedndave
|
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
|
|
|
Logged
|
|
|
|
dedndave
|
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
|
|
|
Logged
|
|
|
|
|
Pages: [1] 2
|
|
|
 |