45

What is the most efficient way to change the rounding mode* of IEEE 754 floating point numbers? A portable C function would be nice, but a solution that uses x86 assembly is ok too.

*I am referring to the standard rounding modes of towards nearest, towards zero, and towards positive/negative infinity

Jeff Linahan
  • 3,775
  • 5
  • 37
  • 56
  • please describe your desired rounding mode change in more detail. Some of them do not involve FPU flags, some do. – rwong Jul 29 '11 at 01:35
  • AFAICT, they all involve x87 FPU flags, the RM bits. Toward nearest = 00 (binary), toward -infinity is 01, toward +infinity is 10 and toward zero = 11. – Rudy Velthuis Jul 29 '11 at 01:56

2 Answers2

44

This is the standard C solution:

#include <fenv.h>
#pragma STDC FENV_ACCESS ON

// store the original rounding mode
const int originalRounding = fegetround( );
// establish the desired rounding mode
fesetround(FE_TOWARDZERO);
// do whatever you need to do ...

// ... and restore the original mode afterwards
fesetround(originalRounding);

On backwards platforms lacking C99 support, you may need to resort to assembly. In this case, you may want to set the rounding for both the x87 unit (via the fldcw instruction) and SSE (via the ldmxcsr instruction).

Edit You don't need to resort to assembly for MSVC. You can use the (totally non-standard) _controlfp( ) instead:

unsigned int originalRounding = _controlfp(0, 0);
_controlfp(_RC_CHOP, _MCW_RC);
// do something ...
_controlfp(originalRounding, _MCW_RC);

You can read more about _controlfp( ) on MSDN.

And, just for completeness, a decoder ring for the macro names for rounding modes:

rounding mode    C name         MSVC name
-----------------------------------------
to nearest       FE_TONEAREST   _RC_NEAR
toward zero      FE_TOWARDZERO  _RC_CHOP
to +infinity     FE_UPWARD      _RC_UP
to -infinity     FE_DOWNWARD    _RC_DOWN
Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
  • 3
    Technically this requires `#pragma STDC FENV_ACCESS ON` to work, though most compilers make it so it "usually" works without that, and ignore the `#pragma`... – R.. GitHub STOP HELPING ICE Jul 29 '11 at 01:35
  • "Backwards platforms" :-) On these, you could just write a drop-in `fesetenv` function in asm... – R.. GitHub STOP HELPING ICE Jul 29 '11 at 01:38
  • @R..: yeah, I added the pragma as you were writing your comment. – Stephen Canon Jul 29 '11 at 01:39
  • ... and if we're going to be really pedantic, I should have checked the return code from `fesetround`, and the result of `fegetround` =) – Stephen Canon Jul 29 '11 at 01:41
  • An example implementation would be great. (VC++ apparently is not a C99 compiler :-) – Jeff Linahan Jul 29 '11 at 01:46
  • 3
    for completeness: "nearest" on x86 is "nearest even", in case anyone is wondering. – Pod May 29 '14 at 14:27
  • 5
    @Pod: If we're is going to be pedantic, let's get it right. "Round to nearest, ties to even" is the default rounding mode on all IEEE-754 conforming systems. – Stephen Canon May 29 '14 at 15:52
  • 1
    Is that not supposed to be `_controlfp` for MSVC? – J Evans Dec 31 '14 at 17:55
  • C++ has a [cfenv](http://www.cplusplus.com/reference/cfenv/) library since C++11. –  Oct 04 '15 at 22:49
  • Please fix the function name for MSVC: It must be _controlfp( ) and not _control_fp( ). – Kaiserludi Jan 10 '19 at 18:43
  • @Kaiserludi: done, but it's probably better to edit yourself (or proposed edits) in the future. – Stephen Canon Jan 11 '19 at 01:53
  • 1
    I was attempting to edit it myself, but was prevented from doing it by the site, as fixing all occurrences only resulted in 6 changed characters and one has to change at least 10 characters when one edits someone-else post, or the edit is not possible. As I did not find it appropriate to change something else in your post for no reason other than hitting the character limit, I concluded that asking you to edit your post would be the best course of action for me. – Kaiserludi Jan 11 '19 at 11:07
-5

this might help.

Edit: I would say you would need your own function. You can use assembly inside C.

But if you register size is 64bits, round it to 32bit would make your calculations faster. It will actually make it slower. Remember 64bit calculations is easy for a 64 microprocessor rather than 2-32bit. I don't know what exactly you want to achieve. I know performance is on your criteria.

TheTechGuy
  • 16,560
  • 16
  • 115
  • 136
  • 1
    that looks like it rounds things to integers. I was looking for a way to change the way rounding to the nearest machine representable number is done. – Jeff Linahan Jul 29 '11 at 01:34
  • 1
    I think you're answering a slightly different question than OP's. Although you *can* use these (along with scaling functions) to perform arbitrary rounding of results, it's a lot painful and slower than setting the rounding mode. – R.. GitHub STOP HELPING ICE Jul 29 '11 at 01:37
  • I am thinking you have to write your own function for that. You can use assembly inside c. That will make an efficient function – TheTechGuy Jul 29 '11 at 01:49
  • Link-only answer. – einpoklum Aug 29 '16 at 09:17