This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Rounding floats to integers on Cortex-M4

I've encountered an odd problem on STM32F4xx CPU with hardware FPU enabled:

When rounding floats to integers, compiler always uses VCVT (round towards zero) instruction instead of VCVTR (round using rounding mode register settings).

There are compiler options for various IEEE compatibility modes, some of them explicitly define "round to nearest" behaviour, but it seems to be ignored.

Even worse, FLT_ROUNDS in float.h  is defined as floats are rounded, but they're truncated.

fpgetround() and fpsetround() do not work right either.

Any ideas?

Parents
  • To solve the problem, you could make 2 macros; one for rounding towards zero and one for rounding normally by first adding 0.5.

    That would also make sure that switching rounding mode would not affect your results.

    By doing that, you would also be sure that no matter which compiler that is used to generate the binaries, you would get the same results.

    It could be something like the following (for 32-bit unsigned integers):

    #define FLOOR32U(f) ((uint32_t) (f))

    #define ROUND32U(f) FLOOR32U((f) + 0.5)

    If you need signed integers, it would be a good idea to use ABS in the macros.

    Unfortunately, the CEIL32U is a bit more complicated than I first expected, because if the value is already an integer, it should not be incremented.

    Adding 1 after rounding the value up would not work then. Adding 0.9999999 is just not very reliable either.

Reply
  • To solve the problem, you could make 2 macros; one for rounding towards zero and one for rounding normally by first adding 0.5.

    That would also make sure that switching rounding mode would not affect your results.

    By doing that, you would also be sure that no matter which compiler that is used to generate the binaries, you would get the same results.

    It could be something like the following (for 32-bit unsigned integers):

    #define FLOOR32U(f) ((uint32_t) (f))

    #define ROUND32U(f) FLOOR32U((f) + 0.5)

    If you need signed integers, it would be a good idea to use ABS in the macros.

    Unfortunately, the CEIL32U is a bit more complicated than I first expected, because if the value is already an integer, it should not be incremented.

    Adding 1 after rounding the value up would not work then. Adding 0.9999999 is just not very reliable either.

Children