News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

fpu example

Started by jcfuller, March 26, 2013, 11:10:51 PM

Previous topic - Next topic

jcfuller

Sorry if this is the wrong place for this.
My fpu coding is horrid at best.
How would you code this "c" example in this post of mine.(jwasm or masm)
http://cboard.cprogramming.com/c-programming/155373-verify-mingw-issue.html
Do you feel it is unrealistic to expect 1267?
It is beginning to appear only gcc and BCc 5.5 return 1266.

James

jj2007

The result depends only on the FPU rounding mode. If it's "down", then 1266.9999999999997730 becomes indeed 1266...

include \masm32\include\masm32rt.inc
.code
start:
   fld FP8(12.67)
   push 100
   fild dword ptr [esp]
   fmul
   fistp dword ptr [esp]
   pop eax
   inkey str$(eax)
   exit
end start

MichaelW

Yes, using the FPU directly, and with everything at the defaults I get 1267, but by changing the rounding mode I can get 1266.

;==============================================================================
    include \masm32\include\masm32rt.inc
;==============================================================================

FRC_NEAREST   equ  0     ; or to even if equidistant (initialized state)
FRC_DOWN      equ 400h   ; toward -infinity
FRC_UP        equ 800h   ; toward +inifinity
FRC_TRUNCATE  equ 0c00h  ; toward zero

SETRC MACRO rc
    IFNDEF __fpu__cw__
        .data?
            __fpu__cw__ dw ?
        .code
    ENDIF
    fstcw __fpu__cw__
    and __fpu__cw__, NOT 0c00h
    or  __fpu__cw__, rc
    fldcw __fpu__cw__
ENDM

;==============================================================================
    .data
    .code
;==============================================================================
foo proc d:REAL8
    printf("%.15G\n", d)
    fld8 100.0
    fld d
    fmul
    push eax
    fistp DWORD PTR [esp]
    pop eax
    ret
foo endp
;==============================================================================
start:
;==============================================================================
    invoke foo, FP8(12.67)
    printf("%d\n",eax)
    SETRC FRC_DOWN
    invoke foo, FP8(12.67)
    printf("%d\n",eax)
    SETRC FRC_UP
    invoke foo, FP8(12.67)
    printf("%d\n",eax)
    SETRC FRC_TRUNCATE
    invoke foo, FP8(12.67)
    printf("%d\n\n",eax)

    inkey
    exit
;==============================================================================
end start


12.67
1267
12.67
1266
12.67
1267
12.67
1266


In the C code you should be able to display the current FPU rounding mode, but then there is the possibility that one is using SSE2 instead of the FPU, and I can't conveniently test the effects of that ATM.
Well Microsoft, here's another nice mess you've gotten us into.

qWord

Quote from: jcfuller on March 26, 2013, 11:10:51 PMthis "c" example
According to the C (ISO) standard, floating point values are truncated when they are converted to integer values (return d*100). Therefore 1266 is conform result.

EDIT: the same applies for c++
MREAL macros - when you need floating point arithmetic while assembling!

jcfuller

I checked the rounding mode with fegetround() and gcc (MinGW),  gcc(MinGwTDM) and PellesC all return zero but as stated
only gcc (MinGW) displays 1266 so it appears something else is causing the difference?

James

qWord

I can reproduce that by setting the precision to REAL10, rounding mode = nearest, doing the calculation and then change the rounding mode to truncate (round to zero).  When storing the integer result, I get also 1266. If the precision is REAL8, 1267 is the result.
You might try to check the constant FLT_EVAL_METHOD.
MREAL macros - when you need floating point arithmetic while assembling!

dedndave

the only place i see "finit" on this page is where Michael mentions infinity   :biggrin:

jcfuller

Thanks everyone.
As I never do any thing in moderation and can become obsessed at the drop of a ... I persisted to see why the difference?

This is my latest test piece. When compiled with the newest 32bit gcc 4.8.0 only the first one displays 1266

James


#include <stdio.h>
#include <math.h>
int     foo (double);
int     main (int,char**);

int foo (double d)
{
  printf("%s% .15G\n","d = ",(double)d);
return (d*100);      // 1266
//return ceil(d*100);  // 1267
//return floor(d*100); // 1267
//return trunc(d*100); // 1267
//return round(d*100);   // 1267
}

int main (int argc,char** argv)
{
  int      rv={0};
  double d =12.67;
  rv= foo( d);
  printf("%s% d\n","rv = ",(int)rv);
  return 0;
}

jj2007

Quote from: dedndave on March 27, 2013, 01:53:12 AM
the only place i see "finit" on this page is where Michael mentions infinity   :biggrin:

On program entry the FPU setting is NEAR, 53 bits. Here is an extended example.

include \masm32\include\masm32rt.inc
.code
start:

   fld FP8(12.67)
   push 100
   fild dword ptr [esp]
   fmul
   fistp dword ptr [esp]
   pop eax
   print str$(eax), 13, 10 ; default setting is NEAR, 53 ->1267

  push 847Fh ; DOWN, 24 ->1266
   fldcw word ptr [esp]
   pop eax

   fld FP8(12.67)
   push 100
   fild dword ptr [esp]
   fmul
   fistp dword ptr [esp]
   pop eax
   print str$(eax), 13, 10

  push 807Fh ; NEAR, 24 ->1267
   fldcw word ptr [esp]
   pop eax

   fld FP8(12.67)
   push 100
   fild dword ptr [esp]
   fmul
   fistp dword ptr [esp]
   pop eax
   inkey str$(eax)

   exit
end start


qWord

As it has already said, there are two problem: one is the different evaluation precision of the compilers and the other is the truncation on double->int conversion.
If you get 1266 or 1267, depends of the result of d*100: if the result is a bit larger or equal than 1267, it will be truncate to this number, otherwise it will get 1266.
Many C/C++ compiler use 53 Bit precision for evaluation, where the calculation's result seems to be  a bit larger (or equal) than 1267 (due rounding of the result). GCC (32Bit) does use 64 Bit precision and the result is below 1267. Therefore GCC truncate the result to 1266 whereas the other compilers shows the intuitive result. For the other function (ceil, floor,...) it is that they have a double argument, thus GCC will do a conversion from 64 to 53 bit precision -> the value gets 1267 before the actual function is called.
MREAL macros - when you need floating point arithmetic while assembling!

dedndave

Jochen, yes - that's how the windows os sets it up for us
but, the C compiler init code may set it up differently

Adamanteus

I could remark that in all cases got 1267, so my opinion that it's gone from differ bitwise 12.67 constant inputing of differ runtimes. So basically in this topic need hex dump of mentioned values, so we'll never get clear answer.

jcfuller

As I said before MingwTDM,tcc,PellesC,FreeBASIC,PowerBASIC,VC all display 1267.

I am trying to figure out why gcc would or want to be different?

I guess I need to find out how to communicate with the builders.

James

Edit: gcc on 32bit linux displays 1266 also.

Gunther

Hi James,

Quote from: jcfuller on March 27, 2013, 04:37:30 AM
As I said before MingwTDM,tcc,PellesC,FreeBASIC,PowerBASIC,VC all display 1267.

I am trying to figure out why gcc would or want to be different?

I guess I need to find out how to communicate with the builders.

James

Edit: gcc on 32bit linux displays 1266 also.

yes, and that's all right, because it has to do with the C standard. Qword did explain it very well. The answer to your question is in reply #3 and #9 of this thread.

Gunther
You have to know the facts before you can distort them.

jcfuller

Gunther,
  Yes I did read that a little fast and it does answer the what (thanks Qword) but it still does not answer the why when it appears almost all (clang on 32bit linux returns 1267 too) other compilers use 53 bit??

James