The MASM Forum

Projects => Rarely Used Projects => GoAsm => Topic started by: shankle on February 28, 2015, 01:57:08 PM

Title: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on February 28, 2015, 01:57:08 PM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Yuri on February 28, 2015, 02:42:47 PM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on February 28, 2015, 02:58:30 PM
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:
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: FORTRANS on March 01, 2015, 12:50:52 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 01, 2015, 12:54:28 AM
Thanks guys for your response.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 01, 2015, 11:38:44 AM
Sorry Fortrans the file unzipped is not compatible with Windows 7.
Maybe you know some other way of reading it?
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: FORTRANS on March 01, 2015, 11:50:46 PM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Gunther on March 02, 2015, 07:08:46 PM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 03, 2015, 02:17:42 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 06, 2015, 11:53:50 AM
        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"   
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 06, 2015, 12:07:51 PM
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)
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: rrr314159 on March 06, 2015, 03:43:06 PM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Yuri on March 06, 2015, 05:46:36 PM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: rrr314159 on March 06, 2015, 06:31:01 PM
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!
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: 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. 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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 07, 2015, 12:03:38 AM
not sure i see an advantage in that Michael
seems like more work   :redface:
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 07, 2015, 12:44:18 AM
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"
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: MichaelW on March 07, 2015, 12:53:52 AM
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.

Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: GoneFishing on March 07, 2015, 02:10:42 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Yuri on March 07, 2015, 02:26:58 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 07, 2015, 06:51:58 AM
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 ...
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 07, 2015, 07:33:15 AM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: rrr314159 on March 07, 2015, 10:34:49 AM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Yuri on March 07, 2015, 05:47:36 PM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 08, 2015, 01:53:51 AM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 09, 2015, 06:15:05 AM
        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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 09, 2015, 08:02:00 AM
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]
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 09, 2015, 08:06:02 AM
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)
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 09, 2015, 10:40:43 AM
Just a tad of clarification Dave.
Is [rsp] a typo or the 32-bit esp register?
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 09, 2015, 11:08:34 AM
RSP is the 64-bit wide stack pointer, counterpart to the 32-bit ESP

i'm assuming that you are writing 64-bit code
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 09, 2015, 11:55:02 AM
        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

Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 09, 2015, 12:01:05 PM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Yuri on March 09, 2015, 03:09:43 PM
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
---------------------------
ОК   
---------------------------
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 09, 2015, 04:43:32 PM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Yuri on March 09, 2015, 09:29:55 PM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 10, 2015, 10:48:19 AM
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?
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 10, 2015, 11:42:38 AM
https://msdn.microsoft.com/en-us/library/5948ysye.aspx (https://msdn.microsoft.com/en-us/library/5948ysye.aspx)
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 10, 2015, 11:44:00 PM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Yuri on March 11, 2015, 01:50:32 AM
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?
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 11, 2015, 02:34:21 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 11, 2015, 03:17:23 AM
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?
 

Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 11, 2015, 03:21:22 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 15, 2015, 07:48:04 AM
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?
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: FORTRANS on March 15, 2015, 08:59:35 AM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Yuri on March 15, 2015, 02:33:18 PM
Quote from: shankle on March 15, 2015, 07:48:04 AM
Figures are a tad high.
Could you clarify what you mean by that?
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 15, 2015, 11:04:48 PM
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. 
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 16, 2015, 12:24:54 AM
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"
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 16, 2015, 12:27:54 AM
let's use your previous example:

1.00416 / 15

0.06694399999999999

what do you want to see as a result ?
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 16, 2015, 12:30:54 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 16, 2015, 01:02:05 AM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 16, 2015, 01:10:02 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 16, 2015, 01:39:33 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 16, 2015, 01:58:10 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 16, 2015, 02:02:50 AM
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)
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 16, 2015, 02:19:38 AM
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 ...

Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 17, 2015, 02:08:36 AM
        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

Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 17, 2015, 02:30:35 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 17, 2015, 03:08:29 AM
Sorry - Typo :biggrin:
HoldValue should be DB
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 19, 2015, 02:32:25 AM
        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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 19, 2015, 02:49:37 AM
try "%9.2g" format
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Yuri on March 19, 2015, 03:29:32 AM
I doubt it's a question of format. The code works correctly for me with just "%g".
Quote
---------------------------
Result
---------------------------
9980.69
---------------------------
ОК   
---------------------------
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 24, 2015, 02:18:49 AM
        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
   
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: jj2007 on March 24, 2015, 02:31:53 AM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: FORTRANS on March 24, 2015, 03:21:50 AM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 24, 2015, 03:37:54 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 24, 2015, 03:42:55 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 24, 2015, 12:11:29 PM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: jj2007 on March 24, 2015, 12:33:08 PM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 24, 2015, 01:11:35 PM
also, visit the main page - scroll down to the bottom

http://www.ray.masmcode.com/ (http://www.ray.masmcode.com/)
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: rrr314159 on March 24, 2015, 02:00:51 PM
this tutorial was my "bible" learning the FPU - thanks Raymond!
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 25, 2015, 12:53:12 AM
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:
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 25, 2015, 07:04:57 AM
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
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Yuri on March 25, 2015, 04:29:46 PM
shankle
What 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
---------------------------
ОК   
---------------------------
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 26, 2015, 12:02:28 AM
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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: Yuri on March 26, 2015, 01:32:55 AM
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
---------------------------
ОК   
---------------------------
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 26, 2015, 01:26:03 PM
        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.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 26, 2015, 01:56:05 PM
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)
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: MichaelW on March 26, 2015, 05:30:35 PM
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

Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: dedndave on March 26, 2015, 05:42:30 PM
it's crt__atodbl in msvcrt.inc   :biggrin:
Jack uses GoAsm, which handles imports differently i guess
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: MichaelW on March 26, 2015, 06:05:10 PM
I should have specified that I was only looking at the 64-bit components.
Title: Re: multiplying/dividing a positive decimal number by a positive number
Post by: shankle on March 26, 2015, 10:12:55 PM
        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.