So on a computer how to div/mul a positive decimal number by a positive number?
Ex: 1.00416 by 15??? If this involves Floating Point math then I will have to start from scratch.
Works fine on a calculator but loses the decimal places on the computer.
Yes, you will have to use the FPU.
DATA SECTION
n1 DQ 1.00416
n2 DQ 15.0
n3 DQ 0
CODE SECTION
Start:
fld Q[n1] ; Load n1 into the ST0 register on the FPU stack.
fdiv Q[n2] ; Divide it by n2 directly from memory.
fstp Q[n3] ; Pop the result off the stack to memory.
#if x64 ; Show the result.
invoke msvcrt:printf, "%g / %g = %g", [n1], [n2], [n3]
#else
invoke msvcrt:printf, "%g / %g = %g", [n1], [n1+4], [n2], [n2+4], [n3], [n3+4]
add esp,1Ch
#endif
ret
well - learning to use the FPU is a good idea, and the results will be much faster
but, you can use "fixed point" math, as an alternative
1.00416 x 100000 = 100416
you can then divide 100416 by 15 using DIV
understand that the result is 100,000 times the desired answer
you can convert it to a string, and insert the decimal point :biggrin:
Hi,
In the old forum I posted a DOS program to show how fixed point
arithmetic works. Sort of.
http://www.masmforum.com/archive2012/5486_FIX2DEC.zip
I think that is it.
Steve
Thanks guys for your response.
Sorry Fortrans the file unzipped is not compatible with Windows 7.
Maybe you know some other way of reading it?
HI,
You can install a DOS emulator or virtual machine to run
16-bit programs. DOSBOX, Bochs, and Virtual PC have been
mentioned by others as good solutions.
As that program uses the BIOS to write to video memory in CGA
mode 3, I do not think it a good program to translate to 32-bit (64-bit?)
Windows. Dave, or others, can correct me if I have erred in my
estimate.
Steve
Hi shankle,
for the operation you can use the XMM registers, too.
For the program provided by FORTRANS you could use the VMWare Player as another alternative for the Virtual Machine.
Gunther
Jack,
i used fixed-point math to display the Gamma value in the status bar
http://masm32.com/board/index.php?topic=4052.msg42784#msg42784 (http://masm32.com/board/index.php?topic=4052.msg42784#msg42784)
the track bar gives you integers (i used 0 to 400, in this case)
i convert those values to a range of 033 to 300
then, i display the value in the status bar by inserting a decimal point in the string (0.33 to 3.00)
later, i use the converted integer to perform floating point math
i load it into the FPU and divide by 100 for those calculations
but, it's easier to display using fixed-point integer math
3-5-2015
I loaded this code into my 64-bit GoAsm Program.
I got nothing on the screen. Thought that was what msvcrt:printf did.
The program compiled without errors.
I am not familiar with msvcrt:printf.
I gave up on the fixed point suggestion.
Got a lot of invalid results that made no sense.
So something hidden was altering the results.
n1 dq 1.00416
n2 dq 15.0
n3 dq 0
fld Q[n1] ; load n1 into the ST0 register on the fpu stack
fdiv Q[n2] ; divide it by n2 directly from memory
fstp Q[n3] ; pop the results off the stack to memory
invoke msvcrt:printf, "%g / %g = %g", [n1], [n2], [n3]
Tnanks Yuri for the sample code.
Thanks Dave for the pointer to "fpu tutorial by Raymond Filiatreault"
i am not "real" big on printf, either - lol
https://msdn.microsoft.com/en-us/library/wc7014hz.aspx (https://msdn.microsoft.com/en-us/library/wc7014hz.aspx)
shankle, here's how I would do that ...
[edit] woops, didn't realize I was in the GoAsm forum at first, shouldn't have said anything; removed irrelevant material ... ::)
...
GoAsm has some logical ideas, I should check it out further someday
shankle
Yes, it should show the result on the screen. If you just double-click the resulting exe, then probably the console window quickly flashes and disappers and you can't see what is in it. If so, then you can tell it to wait till you press any key, using the "system" function.
DATA SECTION
n1 DQ 1.00416
n2 DQ 15.0
n3 DQ 0
CODE SECTION
Start:
fld Q[n1] ; Load n1 into the ST0 register on the FPU stack.
fdiv Q[n2] ; Divide it by n2 directly from memory.
fstp Q[n3] ; Pop the result off the stack to memory.
#if x64 ; Show the result.
invoke msvcrt:printf, "%g / %g = %g", [n1], [n2], [n3]
invoke msvcrt:system, "echo. & pause"
#else
invoke msvcrt:printf, "%g / %g = %g", [n1], [n1+4], [n2], [n2+4], [n3], [n3+4]
add esp,1Ch
invoke msvcrt:system, "echo. & pause"
add esp,4
#endif
ret
rrr314159
GoLink looks for imported functions directly in DLLs, so the "msvcrt" prefix is the name of the DLL. The ".dll" extension can be omitted. DLLs can also be bound with the #dynamiclinkfile directive in source code or specified on GoLink's command line, in that case the prefix is not needed.
Thanks Yuri, that's a very good feature. I got here by clicking on "show unread posts since last visit", didn't realize I was in the GoAsm forum at first, or I would have researched it b4 saying anything.
Thanks for the info!
I realize that the "Real Men" here are going to frown on this, but you can ease the task of using the FPU by creating a simple helper DLL in a HLL (I used Pelles C for this) that provides functions that make it relatively easy to do simple calculations. You need only a single instruction to get the return value into an appropriate variable, FSTP for 32-bit code where FP values are returned on the FPU stack, or MOVLPD for 64-bit code where FP values are returned in XMM0 (at least for Pelles C and I think also for the Microsoft compilers and CRT). The attachment contains the source for the DLL, the 64-bit DLL and import library, the C source and executable for my C test app, and a JWASM 64-bit test app linked with POLINK (sorry, I don't currently have GoAsm installed).
Also, I seem to recall that GoAsm does not use import libraries, so I'm not sure how you should link with the DLL.
not sure i see an advantage in that Michael
seems like more work :redface:
This is my latest attempt....... 3-6-2015
Revision Number two.
I loaded this code into my 64-bit GoAsm Program.
The program compiled without errors.
I changed your code from msvcrt:printf to Textout.
dwtoa has been changed to handle 64-bit registers.
I gave up on the fixed point suggestion.
Got a lot of invalid results that made no sense.
So something hidden was altering the results.
n1 dq 1.00416
n2 dq 15.0
n3 dq 0
fld Q[n1] ; load n1 into the ST0 register on the fpu stack
fdiv Q[n2] ; divide it by n2 directly from memory
fstp Q[n3] ; pop the results off the stack to memory
; test code begin
testout db ' ',0
BufAdd dq 0
hdc dq 0
mov rcx,[n3]
lea rbx,testout
mov [BufAdd],rbx
invoke dwtoa,rcx,[BufAdd] ; Hex DD to string
; output is in testout
invoke TextOut, [hdc],200,600,addr testout,20
; test code end
The result of this code should be 0.066944
This is what I got - 4571453861756211473
Thanks Yuri for the sample code.
Thanks Dave for the pointer to "fpu tutorial by Raymond Filiatreault"
Quote from: dedndave on March 07, 2015, 12:03:38 AM
seems like more work
Floating point operations in a HLL are much easier to understand and code. For a complex series of equations there would be a very large difference in coding effort.
Quote from: MichaelW on March 06, 2015, 09:20:59 PM
I realize that the "Real Men" here are going to frown on this, but you can ease the task of using the FPU by creating a simple helper DLL in a HLL (I used Pelles C for this) that provides functions that make it relatively easy to do simple calculations.
...
Agree with Michael . Realising this fact was one another little step forward in my learning process.
I thought about implementing this (http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtexamp1.htm) in ASM . As I don't have appropriate math background / floating point understanding I desided to make first draft in C++ and it took 100 lines of code to do that.
I borrowed Vec structure from famous on internet SMALLPT program :
struct Vec {
double x, y, z;
Vec(double x_=0, double y_=0, double z_=0){ x=x_; y=y_; z=z_; }
Vec operator+(const Vec &b) const { return Vec(x+b.x,y+b.y,z+b.z); }
Vec operator-(const Vec &b) const { return Vec(x-b.x,y-b.y,z-b.z); }
Vec operator*(double b) const { return Vec(x*b,y*b,z*b); }
Vec mult(const Vec &b) const { return Vec(x*b.x,y*b.y,z*b.z); }
Vec& norm(){ return *this = *this * (1/sqrt(x*x+y*y+z*z)); }
double dot(const Vec &b) const { return x*b.x+y*b.y+z*b.z; } // cross:
Vec operator%(Vec&b){return Vec(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);}
};
How much lines of code will it take in ASM ?
P.S.: Moreover, it's a good way to learn from compiler - he(or she?) does know SSE better and I can tell him(or her?) to optimize my code for , say, SSE2
shankle
n3 is not an integer. It's in a floating point format, so you can't use dwtoa to convert it to a string. You need a function that does the same for floating point numbers. Or you can use one of the msvcrt.dll's functions.
DATA SECTION
n1 DQ 1.00416
n2 DQ 15.0
n3 DQ 0
buf DB 100 DUP ?
CODE SECTION
Start:
fld Q[n1] ; Load n1 into the ST0 register on the FPU stack.
fdiv Q[n2] ; Divide it by n2 directly from memory.
fstp Q[n3] ; Pop the result off the stack to memory.
invoke msvcrt:sprintf_s, addr buf, sizeof buf, "%g / %g = %g", [n1], [n2], [n3]
invoke user32:MessageBoxA, 0, addr buf, "Result", 0
ret
hi Jack
i wrote this little test program
of course, it's 32-bit MASM syntax, but it might help
all you need is a 64-bit equiv of the FloatToStr2 function, which is part of the Masm32 library
i used REAL8's, because that's what the FloatToStr2 function uses
INCLUDE \Masm32\Include\Masm32rt.inc
;###############################################################################################
.DATA
n1 REAL8 1.00416
n2 REAL8 15.0
n3 REAL8 0.0
;***********************************************************************************************
.DATA?
buf db 20 dup(?)
;###############################################################################################
.CODE
;***********************************************************************************************
main PROC
fld n1 ; Load n1 into the ST0 register on the FPU stack.
fdiv n2 ; Divide it by n2 directly from memory.
fstp n3 ; Pop the result off the stack to memory
INVOKE FloatToStr2,n3,offset buf
print offset buf
print chr$(13,10)
inkey
INVOKE ExitProcess,0
main ENDP
;###############################################################################################
END main
result:
0.06694399999999999
Press any key to continue ...
Thanks Dave and thanks for realizing I'm just a novice with FPU.
I tried your little proggie and the compiler complained that "Floattostr2
was not defined. I was unable to find any trace of it in GoAsm 64.
That does not mean it's not there.
In the mean time Yuris example does not work for me either.
I have no idea what goes in "Result". I would think it would be n3.
Anyway the example with "Result" in it gives errors.
shankle, this suggestion may be useless to you but, just to learn about FPU, u could drop back to 32-bit MASM and do it there. Nothing wrong with GoAsm or 64-bit but there are many more examples in good ol' MASM32 world. Figure it out with that tool, then it's easy to translate to other environments.
This is not to denigrate GoAsm, which looks like fine product, 64-bit, which I prefer, or Yuri's help; but he's only one person; dozens can help with MASM32.
Quote from: shankle on March 07, 2015, 07:33:15 AM
Anyway the example with "Result" in it gives errors.
What errors does it give? Did you compile it as a standalone exe or put it in your program? It compiles and runs without errors for me.
Thanks Yuri,
Your response made me take a closer look at the code I typed.
And yes, I made a typo. :redface: Your code is now working.
3-8-2015
This code gives the wrong value in GoAsm 64-bit
Value should be 0.006
Incorrect value is 280461;
hdc dq 0
n1 dq 0
n2 dq 15 ;fixed value
n3 dq 0 ; result
buf db ' ',0
HoldValue db ' ',0 ; keyed in variable input ex: 0.090
lea rcx,HoldValue ; value is keyed input
mov [n1],rcx ; (This is what I don't know how to do)
fld Q[n1] ;load n1 into the ST0 register on the fpu stack
fdiv Q[n2] ; divide it by n2 directly from memory
fstp Q[n3] ; pop the results off the stack to memory
invoke msvcrt:sprintf_s,addr buf,sizeof buf,\
"%g",[n3]
invoke TextOut, [hdc],200,345,addr buf,7
you want to use FILD (float integer load), instead of FLD (float load)
the value from RCX must be in memory
so, i sometimes just PUSH it on the stack and load it from there
push rcx
fild qword ptr [rsp] ;we have to tell the assembler the size of the integer
;
;
;
pop rcx
i guess, for GoAsm, it would be
fild Q[rsp]
by the way, when you load an integer into the FPU,
it converts it, internally, to a REAL10 float
(all FPU operations are internally REAL10)
Just a tad of clarification Dave.
Is [rsp] a typo or the 32-bit esp register?
RSP is the 64-bit wide stack pointer, counterpart to the 32-bit ESP
i'm assuming that you are writing 64-bit code
3-8-2015
Thanks Dave for helping.
This code gives the wrong value in GoAsm 64-bit
Value should be 0.006
Incorrect value is 1.#nf
hdc dq 0
n1 dq 0
n2 dq 15 ;fixed value
n3 dq 0 ; result
buf db ' ',0
; keyed in value is 0.090 in HoldValue
HoldValue db ' ',0 ; keyed in variable input ex: 0.090
lea rcx,HoldValue ; this includes the decimal point
invoke atodw,rcx ; decimal string to DWORD(now in Hex)
push rax
fild Q[rsp] ; load HoldValue into the ST0 register on the fpu stack
fdiv Q[n2] ; divide it by n2 directly from memory
fstp Q[n3] ; pop the results off the stack to memory
invoke msvcrt:sprintf_s,addr buf,sizeof buf,\
"%g",[n3]
invoke user32:MessageBoxA,0,addr buf,"Result",0
invoke TextOut, [hdc],200,345,addr buf,7
pop rax
in order for the assembler to assign floating point constants, you must use real format
n1 dq 0.0
n2 dq 15.0 ;fixed value
n3 dq 0.0 ; result
i am not familiar with GoAsm, but with Masm, we use REAL8 instead of DQ
that way, the code does not need to be told the size
but - my guess is that the integer 15 is not the same as the REAL8 15.0
also - you could make your keyboard input buffer a bit larger :P
Yes, dq 15 and dq 15.0 are two different formats and we should not substitute one for the other. 0 and 0.0 must be the same, though.
DATA SECTION
n1 DQ 0
n2 DQ 15.0
n3 DQ 0
buf DB 100 DUP ?
HoldValue DB "0.090",0
CODE SECTION
Start:
invoke msvcrt:_atodbl, addr n1, addr HoldValue ; Convert string to double.
fld Q[n1] ; Load n1 into the ST0 register on the FPU stack.
fdiv Q[n2] ; Divide it by n2 directly from memory.
fstp Q[n3] ; Pop the result off the stack to memory.
invoke msvcrt:sprintf_s, addr buf, sizeof buf, "%g / %g = %g", [n1], [n2], [n3]
invoke user32:MessageBoxA, 0, addr buf, "Result", 0
ret
Quote
---------------------------
Result
---------------------------
0.09 / 15 = 0.006
---------------------------
ОК
---------------------------
right, Yuri - as it happens, 0.0 = 0
but - he's not loading those :P
if you want to specify a real initializer, use a decimal point
Sorry, Dave, but I don't see how it would make any difference. As far as I know, integer and floating point zeroes are both a bunch of zero bits.
However, I agree with your recommendation. Specifying 0.0 would be more logically correct and would also remind about the format of the number.
Thanks guys for responding.
Had a bunch of "HoneyDos" today but am still working on it....
Changed the 15 to 15.0 as directed. Didn't realize it made a difference.
To Yuri:
Where can I read about "Msvcrt:_atodbl?
https://msdn.microsoft.com/en-us/library/5948ysye.aspx (https://msdn.microsoft.com/en-us/library/5948ysye.aspx)
1. I don't understand why it is necessary to use instructions that are not
part of GoAsm. Ex: any Msvcrt: instruction.
Does that mean that GoAsm can not process the things that Msvcrt: does?
2: want to delete values past 0.01234 - 5 decimal places.
EX 0.01234567 - want to Delete "567". Not round up or down.
1. They are not instructions but functions. You can write your own function that converts a string to a double or vice versa. But if there is already a library of such functions, like msvcrt.dll, you can use them. It's up to you to decide which way you go.
2. Do you mean preventing those digits from showing in the string representation of the number or removing that part of the number itself?
MSVCRT stands for microsoft visual c runtime library
ms c compilers depend on these libraries for many common functions
they are present on all windows computers, so you don't have to worry about checking
the best part about these library functions is that they have been around a long while
and, they have worked out a lot of bugs and improved performance, over time
so - that really reduces your development time and effort
if you have a string, and you want to truncate it, just pick a spot and put the 0 terminator byte in there
example
buffer db '0.1234567',0
mov byte ptr buffer+6,0
now, the string is
buffer db '0.1234',0
Thanks guys for responding.
I think Dave has answered my 2nd ?
The 1st ? I have so far seen 2 Msvcrt: functions used.
Where can I find complete list of these functions?
https://msdn.microsoft.com/en-us/library/5948ysye.aspx (https://msdn.microsoft.com/en-us/library/5948ysye.aspx)
2 important things to notice about that page
first, near the top, there is a drop-down that allows you to view older versions ("Other Versions")
second, in the left pane, there is a clickable list of function names
Figures are a tad high.
Maybe I need to change the Control Word RC field to 0400h
How do I do that?
Is this a correct assumption?
Hi,
The rounding control bits in the FPU control word work as follows.
00 = Round to nearest or even, default.
01 = Round down towards minus infinity.
10 = Round up towards plus infinity.
11 = Chop, truncate towards zero.
Setting the bits with 0400H will round down. From what you were
saying earlier, I think you would want 0C00H to truncate. Of course
if all your numbers are positive, it shouldn't matter much.
HTH,
Steve N.
Quote from: shankle on March 15, 2015, 07:48:04 AM
Figures are a tad high.
Could you clarify what you mean by that?
Let's say the results from the FPU calculations should be 500.
The actual amount is 500.40.
I have not modified the Control Word Rc field.
The code I wrote seems to be basically working.
I am thinking the code is rounding up.
the default is 00, round to nearest
for most applications, that's the right one to use
you are comparing some FPU result to some calculator result, i guess
i'd tend to believe the FPU over most calculators - lol
but - you were talking about limiting the number of digits
setting the FPU to truncate is not the same as truncating the string
QuoteLet's say the results from the FPU calculations should be 500.
The actual amount is 500.40.
not sure when you say "should be"
let's use your previous example:
1.00416 / 15
0.06694399999999999
what do you want to see as a result ?
changing the rounding bits may have undesirable effects for intermediate calculations
that's why i say it's usually best to use "round to nearest"
then, massage the resulting string to suit your needs
In a previous post I limited the resolution to 5 decimal places.
So in answer to Dave it would be .00694.
Since I have not modified the Control Word, I assume it's set to the default.
0.06694399999999999
^
i would go one digit past the carot above, that would be a "3"
because that digit is less than "5", simply truncate to the "4" by placing a null where the "3" is
if that digit were "5" or higher, i would truncate the same way, but add one to the remaining string
notice that, when you add one, you have to ripple carry :P
in some cases, ripple carry might cause the string to lengthen - lol
a better solution might be to have a floating point conversion routine that sets the number of returned digits
PROBLEM SOLVED! - (I Think)
Using the longer decimal resolutions fixed the problem.
I think I will be a FPU Expert in about another 99.9999 years :biggrin: :biggrin: :biggrin:
Thanks guys
it just occured to me that the MSVCRT probably has a function to do this
i don't use it much but let me look around a bit
looks like printf can do what you like
MSDN reads like stereo instructions
but, here's a tutorial that might be easier to understand...
http://www.codingunit.com/printf-format-specifiers-format-conversions-and-formatted-output (http://www.codingunit.com/printf-format-specifiers-format-conversions-and-formatted-output)
here's a quick go at it
this works for console mode
for gui mode, you might have to create a buffer and use fprintf or sprintf (i don't know which)
as it happens, crt_printf wants to see a double (REAL8)
;###############################################################################################
.XCREF
.NoList
INCLUDE \Masm32\Include\Masm32rt.inc
.List
;###############################################################################################
.DATA
n1 REAL8 1.00416
n2 REAL8 15.0
szFloatFormat db "%7.5f",0
;***********************************************************************************************
.DATA?
n3 REAL8 ?
;###############################################################################################
.CODE
;***********************************************************************************************
main PROC
fld n1 ; Load n1 into the ST0 register on the FPU stack.
fdiv n2 ; Divide it by n2 directly from memory.
fstp n3 ; Pop the result off the stack to memory
INVOKE crt_printf,offset szFloatFormat,n3
print chr$(13,10)
inkey
exit
main ENDP
;###############################################################################################
END main
szFloatFormat db "%7.5f",0
at least 7 wide, with precision of 5
result
0.06694
Press any key to continue ...
3-16-2015
Thanks for any help.
n1 dq 0
buf db ' ',0
HoldValue dd '0010000.00 ',0
This code does not work
The decimal places are not showing up in the TextOut instruction.
The documentation is confusing and I can't tell which atodbl addresses
decimal points
The value from n1 shows in TextOut as 0010000.
invoke msvcrt:_atodbl, addr n1,addr HoldValue ;convert string to double
invoke msvcrt:sprintf_s, addr buf,sizeof buf,\
"%g",[n1]
invoke TextOut, [hdc],200,345,addr buf,13
HoldValue dd '0010000.00 ',0
did you mean "DD" or "DB" ?
anyways....
if the fraction part is 0, it won't appear
that's pretty normal float-to-string behaviour
Sorry - Typo :biggrin:
HoldValue should be DB
3-18-2015
Thanks for any help.
n1 dq 0
Value dq 19.31
buf db ' ',0
HoldValue db '0010000.00 ',0
This code does not work
The decimal places are not showing up in the TextOut instruction.
The Microsofts documentation is confusing and I can't tell which _atodbl
to use. Maybe I am using the wrong one.
invoke msvcrt:_atodbl, addr n1,addr HoldValue ;convert string to double
fld Q[n1] ; load n1 into the ST0 register on the fpu stack
fsub Q[Value] ; subtract Value from amount in ST0
fstp Q[n1] ; pop the results off the stack to memory
invoke msvcrt:sprintf_s,addr buf,sizeof buf,\
"%g",[n1]
invoke TextOut, [hdc],200,345,addr buf,13
The result is 9981 - instead of 9980.69
try "%9.2g" format
I doubt it's a question of format. The code works correctly for me with just "%g".
Quote
---------------------------
Result
---------------------------
9980.69
---------------------------
ОК
---------------------------
3-23-2015
My knowledge about FPU is hovering just above Zero.
fixed dq 12.0
n4 dq 0
buf7 db 8 DUP (0h)
Value db '.043'
How do I put .043 into the ST0 FPU register
The result from Fild is incorrect
fild D[Value] ;load Value into the ST0 register on the fpu stack
fdiv Q[fixed] ; divide it by 12.0 directly from memory
fstp Q[n4] ; pop the results off the stack to memory
invoke msvcrt:sprintf_s,addr buf7,sizeof buf7,\
"%g",[n4]
invoke TextOut, [hdc],200,425,addr buf7,8
Quote from: shankle on March 24, 2015, 02:18:49 AM
My knowledge about FPU is hovering just above Zero.
Reading Ray's tutorials may help.
Hi,
FILD is to load from an integer variable. FLD loads from a real
valued variable.
Fixed DW 12
Real DD 12.0
FILD [Fixed]
FLD [Real]
Both end up with 12.0 in the FPU. But look at a listing to see
some differences.
Regards,
Steve N.
Value db '.043'
loading it into the FPU is actually the easy part
your big problem here is converting an ASCII string into a float
now, there are a few ways to go about this
one way is to use the masm32 library StrToFloat function
.DATA
r08Value REAL8 ?
Value db '.043'
.CODE
INVOKE StrToFloat,offset Value,offset r08Value
fld r08Value ;load REAL8 into FPU ST(0)
the StrToFloat function only supports REAL8 types
i guess, for GoAsm, the "offset" syntax is a little different
another way would be to convert "0.043" to a fixed-point integer of 43
load the integer and divide it by a constant real of 1000.0
still another way might be to load it using BCD math - i'm not very familiar with that
but, Ray's tutorials and libraries might help
So where is Ray's tutorial?
I read about the lib from 2012 and it had errors.
Have they been fixed?
I will gladly give it a read if I can find it.
Quote from: shankle on March 24, 2015, 12:11:29 PM
So where is Ray's tutorial?
Google is your friend: http://www.ray.masmcode.com/tutorial/index.html
also, visit the main page - scroll down to the bottom
http://www.ray.masmcode.com/ (http://www.ray.masmcode.com/)
this tutorial was my "bible" learning the FPU - thanks Raymond!
Thanks guys,
I should have known about this weeks ago.
In my short perusal so far I think "fpulib" is a gold mine.
BUT, FpuAtoFl shows an error for this instruction.
So I need the equivalent of Raymonds tutorial for GoAsm.
I don't think it exists. :(
And yes, Thanks Raymond :biggrin:
FpuAtoFl sounds like one of Ray's library functions - not the same as an instruction
also - Ray's code is probably 32-bit
you may have to adapt to 64-bit code
shankleWhat happened to _atodbl? Did it stop working for you?
DATA SECTION
fixed dq 12.0
n4 dq 0
buf7 db 16 DUP (0h)
Value db '.043',0
CODE SECTION
Start:
invoke msvcrt:_atodbl, addr buf7, addr Value
fld Q[buf7]
fdiv Q[fixed]
fstp Q[n4]
invoke msvcrt:sprintf_s, addr buf7, sizeof buf7, "%g", [n4]
invoke user32:MessageBoxA, 0, addr buf7, "Result", 0
Quote
---------------------------
Result
---------------------------
0.00358333
---------------------------
ОК
---------------------------
Sorry Yuri,
Nothing wrong with atodbl. Guess I thought Ray's stuff would
replace Msvcrt. So if I understand correctly GoAsm will not
support Rays tutorial and I must use Microsofts Msvcrt:xxxxx.
Sorry for the confusion.
The tutorial describes how the FPU works, so it's definitely useful. But fpu.lib is 32-bit, so you can only use it in 32-bit code, like this:
DATA SECTION
DEST_MEM8 EQU 200000h
SRC1_REAL8 EQU 20000h
SRC2_DIMM EQU 800h
fixed dq 12.0
n4 dq 0
buf7 db 16 DUP (0h)
Value db '.043',0
CODE SECTION
Start:
invoke fpu.lib:FpuAtoFL, addr Value, addr buf7, DEST_MEM8
fld Q[buf7]
fdiv Q[fixed]
fstp Q[n4]
invoke fpu.lib:FpuFLtoA, addr n4, 8, addr buf7, SRC1_REAL8 | SRC2_DIMM
invoke user32:MessageBoxA, 0, addr buf7, "Result", 0
ret
Quote
---------------------------
Result
---------------------------
0.00358333
---------------------------
ОК
---------------------------
3-25-2015
n1 dq 0
buf7 db 9 DUP (0h)
Value db '010000.00'
invoke msvcrt:_atodbl, addr n1,addr Value ;convert string to double
invoke msvcrt:sprintf_s, addr buf,sizeof buf,\
"%g",[n1]
invoke TextOut, [hdc],200,425,addr buf7,9
The above drops the ".00"
If I change Value to '010000.11' it still loses the ".11"
Not sure if I am asking the question correctly.
Thanks again for all the help.
try this line, as a test
invoke TextOut, [hdc],200,425,addr Value,9
verify that the area is large enough to support the string length without clipping
oh - and terminate the Value string with a 0
(not needed for TextOut, but might be for the other functions)
I can't see how it can matter, but the floating-point value is supposed to be wrapped in a structure, see the MSDN documentation (https://msdn.microsoft.com/en-us/library/5948ysye.aspx). In the time I spent looking I could not find _atodbl in any import library for MSVCRT.DLL, so I used run-time dynamic linking and call instead of invoke. And since the import library that I used did not include sprintf_s, I just used a routine that calls printf.
;==============================================================================
option casemap:none
include \jwasm\inc\windows.inc
include \jwasm\inc\stdio.inc
include \jwasm\inc\stdlib.inc
includelib \jwasm\lib64\kernel32.lib
includelib \jwasm\lib64\msvcrt.lib
include support.asm
;==============================================================================
_getch PROTO
_CRT_DOUBLE struct
x REAL8 ?
_CRT_DOUBLE ends
;==============================================================================
.data
dblval _CRT_DOUBLE <0.0>
sz_msvcrt db "msvcrt.dll",0
sz_atodbl db "_atodbl",0
s0 db "010000.00",0
s1 db "010000.11",0
s2 db "12345.12345",0
.code
;==============================================================================
main proc
invoke LoadLibrary, ADDR sz_msvcrt
invoke GetProcAddress, rax, ADDR sz_atodbl
mov rbx, rax
sub rsp, 28h
mov rcx, OFFSET dblval
mov rdx, OFFSET s0
call rbx
print("%f\n",dblval.x)
mov rcx, OFFSET dblval
mov rdx, OFFSET s1
call rbx
print("%f\n",dblval.x)
mov rcx, OFFSET dblval
mov rdx, OFFSET s2
call rbx
print("%f\n",dblval.x)
invoke _getch
invoke ExitProcess, 0
main endp
;==============================================================================
end main
Support.asm:
;===================================================================================
; Minimal support components, including several MASM32 macros and one procedure,
; modified and/or renamed as necessary.
;===================================================================================
;include \jwasm\inc\stdio.inc
acfm$ MACRO txt:VARARG
LOCAL ch1,char,nu$,tmp,flag,lbuf,rbuf,cpos,sln
ch1 equ <>
nu$ equ <>
flag = 0
ch1 SUBSTR <txt>,1,1 ;; check if 1st character is a quote
IFDIF ch1,<">
EXITM <txt> ;; exit with original "txt" if it is not
ENDIF
FORC char,<txt> ;; scan through characters in "txt"
IFIDN <char>,<\> ;; increment the flag if "\" escape character
flag = flag + 1
ENDIF
; -----------------------------------------------
IF flag EQ 0 ;; <<< if flag = 0 then normal APPEND character
nu$ CATSTR nu$,<char>
ENDIF
IF flag EQ 1 ;; <<< if flag = 1 then perform replacement
IFIDN <char>,<n>
nu$ CATSTR nu$,<",13,10,"> ;; \n = CRLF
flag = 0
ENDIF
IFIDN <char>,<t>
nu$ CATSTR nu$,<",9,"> ;; \t = TAB
flag = 0
ENDIF
IFIDN <char>,<q>
nu$ CATSTR nu$,<",34,"> ;; \q = quote
flag = 0
ENDIF
IFIDN <char>,<0>
nu$ CATSTR nu$,<",0,"> ;; \0 = embedded zero
flag = 0
ENDIF
;; ---------------------
;; masm specific escapes
;; ---------------------
IFIDN <char>,<l>
nu$ CATSTR nu$,<",60,"> ;; \l = <
flag = 0
ENDIF
IFIDN <char>,<r>
nu$ CATSTR nu$,<",62,"> ;; \r = >
flag = 0
ENDIF
IFIDN <char>,<x>
nu$ CATSTR nu$,<",33,"> ;; \x = !
flag = 0
ENDIF
IFIDN <char>,<a>
nu$ CATSTR nu$,<",40,"> ;; \a = (
flag = 0
ENDIF
IFIDN <char>,<b>
nu$ CATSTR nu$,<",41,"> ;; \b = )
flag = 0
ENDIF
ENDIF
IF flag EQ 2 ;; <<< if flag = 2 APPEND the "\" character
IFIDN <char>,<\>
nu$ CATSTR nu$,<",92,"> ;; \\ = \
flag = 0
ENDIF
ENDIF
; -----------------------------------------------
ENDM
;; ---------------------------------------------
;; strip any embedded <"",> characters sequences
;; ---------------------------------------------
nu$ CATSTR nu$,<,0,0,0> ;; append trailing zeros
cpos INSTR nu$,<"",> ;; test for leading junk
IF cpos EQ 1
nu$ SUBSTR nu$,4 ;; chomp off any leading junk
ENDIF
cpos INSTR nu$,<"",>
WHILE cpos
lbuf SUBSTR nu$,1,cpos-1 ;; read text before junk
rbuf SUBSTR nu$,cpos+3 ;; read text after junk
nu$ equ <> ;; clear nu$
nu$ CATSTR lbuf,rbuf ;; concantenate the two
cpos INSTR nu$,<"",> ;; reload cpos for next iteration
ENDM
sln SIZESTR nu$
nu$ SUBSTR nu$,1,sln-6 ;; trim off tail padding
.data
tmp db nu$,0
align 4
.code
EXITM <OFFSET tmp> ;; return the DATA section OFFSET
ENDM
print MACRO format:REQ, args:VARARG
IFNB <args>
invoke printf, acfm$(format), args
ELSE
invoke printf, acfm$(format)
ENDIF
EXITM <>
ENDM
wait_key proto
_kbhit proto
waitkey MACRO
invoke wait_key
ENDM
.code
wait_key proc
;--------------------------------------------------------------------------
; Unlike the MASM32 lib procedure it was derived from, this procedure does
; not return the pressed key because it needs to avoid the (not Windows8
; compatible) _getch function, and because I simply need to wait for a
; keystroke.
;--------------------------------------------------------------------------
invoke GetStdHandle, STD_INPUT_HANDLE
invoke FlushConsoleInputBuffer, rax
@@:
invoke Sleep, 10
invoke _kbhit
test rax, rax
jz @B
ret
wait_key endp
And the results:
10000.000000
10000.110000
12345.123450
it's crt__atodbl in msvcrt.inc :biggrin:
Jack uses GoAsm, which handles imports differently i guess
I should have specified that I was only looking at the 64-bit components.
3-26-2015
n1 dq 0
looper dd 0
saveesi dd 0
buf7 db ' ',0
Value db ' ',0 ; number keyed in
const
codecode STRUCT
cc1 db ?
cc2 db ?
cc3 db ?
cc4 db ?
codecode ENDS
; program re-enters here 9 times to build the
; keyed input into Value
: keyed in test values: 010000.00 or 010000.11
.ValueLoop
mov ecx,[wParam] ; wParam contains 1 keyed digit of Value
mov D[cc],ecx
mov cl,B[cc.cc1]
mov esi,[saveesi]
mov B[Value+esi],cl
inc esi
mov [saveesi],esi
inc D[looper]
cmp D[looper],9
jne >>.goon ; goes out and comes back to ValueLoop 9 times
invoke msvcrt:_atodbl, addr n1,addr Value ;convert string to double
invoke msvcrt:sprintf_s, addr buf,sizeof buf,\
"%g",[n1]
invoke TextOut, [hdc],200,425,addr buf7,9 ; prints 010000
invoke TextOut, [hdc],200,425,addr Value,9 ; prints 010000.00/010000.11
The above drops the ".00"
If I change the keyed Value to '010000.11',0 it still loses the ".11"
msvcrt:_atodbl can be found on the Microsoft site by keying in _atodbl.
Hope I did a better job this time.