Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Changing FPU rounding mode

639 views
Skip to first unread message

Yipkei Kwok

unread,
Nov 4, 2009, 6:25:05 PM11/4/09
to

Hi,

Problem: After I change the FPU rounding mode with the assembly
instruction fldcw, the rounding mode is reset back to the default
after the program finishes running. How can I make the change
permanent (i.e.until the next time fldcw is called or machine reboot)?

I wrote the following program to change the FPU rounding mode from the
default, `round-to-nearest' (Rounding Control bits=00), to CHOP
(TRUNCATE TOWARD ZERO) (Rounding Control bits=11)

############################# BEGINNING OF THE CODE
#############################
#include <stdio.h>

/** variables to be accessed by assembly code have to be defined */
/** outside functions */

unsigned short old_control_word;
unsigned short new_control_word;
unsigned short current_control_word;

int main(void) {
new_control_word=(short)0x0F7F;

asm(
"pushl %eax \n"
"pushl %ebx \n"
"fstcw old_control_word \n"
"fldcw new_control_word \n"
"fstcw current_control_word \n"
"popl %ebx \n"
"popl %eax \n"
);
printf("old_control_word= %X\n", old_control_word);
printf("current_control_word= %X\n", current_control_word);

return 0;
}
############################# END OF THE CODE
#############################

Here is the output of the program (I ran it twice consecutively).
$ ./a2
old_control_word= 37F
current_control_word= F7F
$ ./a2
old_control_word= 37F
current_control_word= F7F

It appears that the FPU control word was, indeed, changed when fldcw
was called. But, after the execution of the program, the rounding mode
is reset back to the default.

Is there anyway that I can make the change lasts until the next time
fldcw is called, or when the machine reboots?

Thank you very much!

robert...@munged.microcosmotalk.com

unread,
Nov 4, 2009, 8:20:12 PM11/4/09
to

On Nov 4, 5:25=A0pm, Yipkei Kwok <yipkeik...@MUNGED.microcosmotalk.com>
wrote:

> Hi,
>
> Problem: After I change the FPU rounding mode with the assembly
> instruction fldcw, the rounding mode is reset back to the default
> after the program finishes running. How can I make the change
> permanent (i.e.until the next time fldcw is called or machine reboot)?
>
> I wrote the following program to change the FPU rounding mode from the
> default, `round-to-nearest' (Rounding Control bits=3D00), to CHOP
> (TRUNCATE TOWARD ZERO) (Rounding Control bits=3D11)

>
> ############################# BEGINNING OF THE CODE
> #############################
> #include <stdio.h>
>
> /** variables to be accessed by assembly code have to be defined */
> /** outside functions */
>
> unsigned short old_control_word;
> unsigned short new_control_word;
> unsigned short current_control_word;
>
> int main(void) {
> =A0 =A0 =A0 =A0 new_control_word=3D(short)0x0F7F;
>
> =A0 =A0 =A0 =A0 asm(
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "pushl =A0%eax =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\n"
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "pushl =A0%ebx =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\n"
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "fstcw old_control_word =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 \n"
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "fldcw new_control_word =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 \n"
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "fstcw current_control_word =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 \n"
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "popl =A0 %ebx =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\n"
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "popl =A0 %eax =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\n"
> =A0 =A0 =A0 =A0 );
> =A0 =A0 =A0 =A0 printf("old_control_word=3D %X\n", old_control_word);
> =A0 =A0 =A0 =A0 printf("current_control_word=3D %X\n", current_control_wo=
rd);
>
> =A0 =A0 =A0 =A0 return 0;}

>
> ############################# END OF THE CODE
> #############################
>
> Here is the output of the program (I ran it twice consecutively).
> $ ./a2
> old_control_word=3D 37F
> current_control_word=3D F7F
> $ ./a2
> old_control_word=3D 37F
> current_control_word=3D F7F

>
> It appears that the FPU control word was, indeed, changed when fldcw
> was called. But, after the execution of the program, the rounding mode
> is reset back to the default.
>
> Is there anyway that I can make the change lasts until the next time
> fldcw is called, or when the machine reboots?


Change the OS. Essentially all OS's set the FPU flags (and a bunch of
other stuff) to known values when they start a process and/or thread.
They also maintain those setting separately for each process/thread,
so if you change it in one, it won't affect other running programs.

Of course if you make that change, you'll probably break a lot of
programs.

And even considering what the OS does, the CRT startup may be setting
it as well.

But this is almost certainly trying to solve the wrong problem. What
are you trying to accomplish?

Yipkei Kwok

unread,
Nov 4, 2009, 11:41:32 PM11/4/09
to

On Nov 4, 6:20=A0pm, "robertwess...@yahoo.com"
<robertwess...@MUNGED.microcosmotalk.com> wrote:
> On Nov 4, 5:25=3DA0pm, Yipkei Kwok <yipkeik...@MUNGED.microcosmotalk.com>

> wrote:
>
>
>
> > Hi,
>
> > Problem: After I change the FPU rounding mode with the assembly
> > instruction fldcw, the rounding mode is reset back to the default
> > after the program finishes running. How can I make the change
> > permanent (i.e.until the next time fldcw is called or machine reboot)?
>
> > I wrote the following program to change the FPU rounding mode from the
> > default, `round-to-nearest' (Rounding Control bits=3D3D00), to CHOP
> > (TRUNCATE TOWARD ZERO) (Rounding Control bits=3D3D11)

>
> > ############################# BEGINNING OF THE CODE
> > #############################
> > #include <stdio.h>
>
> > /** variables to be accessed by assembly code have to be defined */
> > /** outside functions */
>
> > unsigned short old_control_word;
> > unsigned short new_control_word;
> > unsigned short current_control_word;
>
> > int main(void) {
> > =3DA0 =3DA0 =3DA0 =3DA0 new_control_word=3D3D(short)0x0F7F;
>
> > =3DA0 =3DA0 =3DA0 =3DA0 asm(
> > =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 "pushl =3DA0%eax =3DA0 =
=3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3D
>
> =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0\n"> =3DA0 =3DA0 =3DA0 =3D=
A0 =3DA0 =3DA0 =3DA0 =3DA0 "pushl =3DA0%ebx =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =
=3DA0 =3D
>
> =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0\n"> =3DA0 =3DA0 =3DA0 =3D=
A0 =3DA0 =3DA0 =3DA0 =3DA0 "fstcw old_control_word =3DA0 =3DA0 =3DA0 =3DA0 =
=3D
> =3DA0 =3DA0 =3DA0 =3DA0 \n"
> > =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 "fldcw new_control_word=
=3DA0 =3DA0 =3DA0 =3DA0 =3D
> =3DA0 =3DA0 =3DA0 =3DA0 \n"
> > =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 "fstcw current_control_=
word =3DA0 =3DA0 =3DA0 =3D
>
> =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 \n"> =3DA0 =3DA0 =3DA0 =3DA0 =
=3DA0 =3DA0 =3DA0 =3DA0 "popl =3DA0 %ebx =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA=
0 =3D
>
> =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0\n"> =3DA0 =3DA0 =3DA0 =3D=
A0 =3DA0 =3DA0 =3DA0 =3DA0 "popl =3DA0 %eax =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =
=3DA0 =3D
>
> =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0 =3DA0\n"
>
>
>
>
>
> > =3DA0 =3DA0 =3DA0 =3DA0 );
> > =3DA0 =3DA0 =3DA0 =3DA0 printf("old_control_word=3D3D %X\n", old_contro=
l_word);
> > =3DA0 =3DA0 =3DA0 =3DA0 printf("current_control_word=3D3D %X\n", curren=
t_control_wo=3D
> rd);
>
> > =3DA0 =3DA0 =3DA0 =3DA0 return 0;}

>
> > ############################# END OF THE CODE
> > #############################
>
> > Here is the output of the program (I ran it twice consecutively).
> > $ ./a2
> > old_control_word=3D3D 37F
> > current_control_word=3D3D F7F
> > $ ./a2
> > old_control_word=3D3D 37F
> > current_control_word=3D3D F7F

>
> > It appears that the FPU control word was, indeed, changed when fldcw
> > was called. But, after the execution of the program, the rounding mode
> > is reset back to the default.
>
> > Is there anyway that I can make the change lasts until the next time
> > fldcw is called, or when the machine reboots?
>
> Change the OS. =A0Essentially all OS's set the FPU flags (and a bunch of

> other stuff) to known values when they start a process and/or thread.
> They also maintain those setting separately for each process/thread,
> so if you change it in one, it won't affect other running programs.
>
> Of course if you make that change, you'll probably break a lot of
> programs.
>
> And even considering what the OS does, the CRT startup may be setting
> it as well.
>
> But this is almost certainly trying to solve the wrong problem. =A0What

> are you trying to accomplish?

I am trying to make a Fortran program to conduct some floating point
operations with the CHOP rounding mode. Since there is no way to
change the rounding mode with gfortran code, I want to change the
rounding mode with the little C-assembly program above before running
my Fortran program.

Yes, I know that I can use the ISO C binding to call C code from
Fortran but I just want to see if there is any alternative.

Kevin G. Rhoads

unread,
Nov 5, 2009, 10:57:57 AM11/5/09
to

>I am trying to make a Fortran program to conduct some floating point
>operations with the CHOP rounding mode. Since there is no way to
>change the rounding mode with gfortran code, I want to change the
>rounding mode with the little C-assembly program above before running
>my Fortran program.
>
>Yes, I know that I can use the ISO C binding to call C code from
>Fortran but I just want to see if there is any alternative.

Setup your assembly stuff to be a zero argument subroutine,
call it from the Fortran code as needed. But it makes more sense to
call the C routines that do this.

This issue has been around since the days of 16 bit code for DOS,
here are some old things for MS C & Fortran:
_______________________________________________________________________
$NOTRUNCATE
* Copyright (c) 1994 Kevin G. Rhoads, all rights reserved.
*------------------------------------------------------------------------------
* gets '87 status word
INTERFACE TO INTEGER*2 FUNCTION SSWRQQ()
END
*
*------------------------------------------------------------------------------
* gets '87 status word -- C Library
INTERFACE TO INTEGER*2 FUNCTION
& STAT87[FAR,C,ALIAS:'__status87']()
*
* N.B. ALIAS as supplied uses pre-ANSI (pre MS C/C++v7.0) naming conventions.
* However Microsoft used double leading underscores (a single EXPLICIT leading
* underscore in C declarations) since MS C v5.1 for _status87, _fpreset,
* _control87 and _clear87. The declaration above will link properly with all
* Microsoft C or C/C++ versions from 5.0 through 8.x (VC 1.x).
*
*unsigned int __cdecl _status87(void); /* MS C/C++ 7.0 & later */
*unsigned int _FAR_ _cdecl _status87(void); /* MS C6.0 */
*unsigned int _CDECL _status87(void); /* MS C5.x */
END
*
*------------------------------------------------------------------------------
* gets '87 control word
INTERFACE TO INTEGER*2 FUNCTION SCWRQQ()
END
*
*------------------------------------------------------------------------------
* Sets '87 control word
INTERFACE TO SUBROUTINE LCWRQQ(CW)
INTEGER*2 CW
END
*
*------------------------------------------------------------------------------
* Sets '87 control word -- C library
INTERFACE TO INTEGER*2 FUNCTION
& CTRL87[FAR,C,ALIAS:'__control87'](NEW,MASK)
INTEGER*2 NEW,MASK
*
* N.B. ALIAS as supplied uses pre-ANSI (pre MS C/C++v7.0) naming conventions.
* However Microsoft used double leading underscores (a single EXPLICIT leading
* underscore in C declarations) since MS C v5.1 for _status87, _fpreset,
* _control87 and _clear87. The declaration above will link properly with all
* Microsoft C or C/C++ versions from 5.0 through 8.x (VC 1.x).
*
*unsigned int __cdecl _control87(unsigned int, unsigned int); /* MS C/C++ 7.0
& later */
*unsigned int _FAR_ _cdecl _control87(unsigned int, unsigned int); /* MS C6.0
*/
*unsigned int _CDECL _control87(unsigned int,unsigned int); /* MS C5.x */
END
*
**------------------------------------------------------------------------------
** clears '87 status word and resets FP (C) runtime library
INTERFACE TO SUBROUTINE FPRESET[FAR,C,ALIAS:'__fpreset']()
*
* N.B. ALIAS as supplied uses pre-ANSI (pre MS C/C++v7.0) naming conventions.
* However Microsoft used double leading underscores (a single EXPLICIT leading
* underscore in C declarations) since MS C v5.1 for _status87, _fpreset,
* _control87 and _clear87. The declaration above will link properly with all
* Microsoft C or C/C++ versions from 5.0 through 8.x (VC 1.x).
*
*void __cdecl _fpreset(void); /* MS C/C++ 7.0 & later */
*void _FAR_ _cdecl _fpreset(void); /* MS C6.0 */
*void _CDECL _fpreset(void); /* MS C5.x */
END
*
**------------------------------------------------------------------------------
** gets '87 status word and clears it -- C Library --
** there is (apparently) no way to reset '87 status word in FORTRAN
INTERFACE TO
& INTEGER*2 FUNCTION CLEAR87[FAR,C,ALIAS:'__clear87'] ()
*
* N.B. ALIAS as supplied uses pre-ANSI (pre MS C/C++v7.0) naming conventions.
* However Microsoft used double leading underscores (a single EXPLICIT leading
* underscore in C declarations) since MS C v5.1 for _status87, _fpreset,
* _control87 and _clear87. The declaration above will link properly with all
* Microsoft C or C/C++ versions from 5.0 through 8.x (VC 1.x).
*
*unsigned int __cdecl _clear87(void); /* MS C/C++ 7.0 & later */
*unsigned int _FAR_ _cdecl _clear87(void); /* MS C6.0 */
*unsigned int _CDECL _clear87(void); /* MS C5.x */
END
*
**------------------------------------------------------------------------------
** clears '87 status word and resets FP (C) runtime library
INTERFACE TO SUBROUTINE RESET87[FAR,C,ALIAS:'__fpreset']()
*
* N.B. ALIAS as supplied uses pre-ANSI (pre MS C/C++v7.0) naming conventions.
* However Microsoft used double leading underscores (a single EXPLICIT leading
* underscore in C declarations) since MS C v5.1 for _status87, _fpreset,
* _control87 and _clear87. The declaration above will link properly with all
* Microsoft C or C/C++ versions from 5.0 through 8.x (VC 1.x).
*
*void __cdecl _fpreset(void); /* MS C/C++ 7.0 & later */
*void _FAR_ _cdecl _fpreset(void); /* MS C6.0 */
*void _CDECL _fpreset(void); /* MS C5.x */
END
*

robert...@munged.microcosmotalk.com

unread,
Nov 5, 2009, 10:59:55 AM11/5/09
to

On Nov 4, 10:41=A0pm, Yipkei Kwok <yipkeik...@MUNGED.microcosmotalk.com>
wrote:
> On Nov 4, 6:20=3DA0pm, "robertwess...@yahoo.com"
> > Change the OS. =3DA0Essentially all OS's set the FPU flags (and a bunch=

of
> > other stuff) to known values when they start a process and/or thread.
> > They also maintain those setting separately for each process/thread,
> > so if you change it in one, it won't affect other running programs.
>
> > Of course if you make that change, you'll probably break a lot of
> > programs.
>
> > And even considering what the OS does, the CRT startup may be setting
> > it as well.
>
> > But this is almost certainly trying to solve the wrong problem. =3DA0Wh=

at
> > are you trying to accomplish?
>
> I am trying to make a Fortran program to conduct some floating point
> operations with the CHOP rounding mode. Since there is no way to
> change the rounding mode with gfortran code, I want to change the
> rounding mode with the little C-assembly program above before running
> my Fortran program.
>
> Yes, I know that I can use the ISO C binding to call C code from
> Fortran but I just want to see if there is any alternative.

To the mod: Something appears to be funky at the moderation site -
much of the quoting is escaped.

Anyway, if this is Intel's Fortran on x86/x87, look at SETCONTROLFPQQ.

Terje Mathisen

unread,
Nov 5, 2009, 11:00:46 AM11/5/09
to

Can never work!


>
> Yes, I know that I can use the ISO C binding to call C code from
> Fortran but I just want to see if there is any alternative.

The easiest is probably to (binary) patch the Fortran executable, by
locating the point where the default fp cw is loaded, and modify it to
be the length/rounding mode you want.

The safest is a tiny external asm routine, probably called something
like fldcw(), which you link into the Fortran program. (This is also the
only "proper" way to do it, imho.)

Terje
--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"

0 new messages