1

How to convert float to int according to the current rounding direction?

There are the lrint and llrint functions (C11, 7.12.9.5). However, their return values have types long int and long long int. Why there is no version for int?

pmor
  • 5,392
  • 4
  • 17
  • 36
  • Also, note that an `int` is only guaranteed by the C Standard to be at least 16 bits, so conversion from a 32-bit floating-point type may have been considered (by the committee who defined the `xrint()` functions) to be too dodgy. A `long int` is guaranteed to be at least 32 bits, IIRC, – Adrian Mole Aug 04 '23 at 10:21
  • @AdrianMole Re: "simple cast": consider `lrintf((long)INT_MAX+130)`. The `(long)INT_MAX+130` is out of `int` range. Hence, a native conversion to `int` is expected to raise `FE_INVALID`. However, the `int i = (int)lrint(f);` won't raise `FE_INVALID`. – pmor Aug 04 '23 at 10:38
  • @AdrianMole `(int)lrint(f)` UB – 0___________ Aug 04 '23 at 10:41
  • @0___________ Agreed - comment gone. – Adrian Mole Aug 04 '23 at 10:44
  • @pmor, why did you use `lrintf()` to convert a `float` and not `lrintf()`? – chux - Reinstate Monica Aug 05 '23 at 04:24
  • 1
    @chux-ReinstateMonica Initially I used `lrintf`. Then while comparing results obtained from ARM's `fcvtzs` instruction (and similar instructions for other rounding modes) I've noticed that Invalid FP exception may be missing. Hence, I wondered why there is no `irintf` and asked this question. While waitning an answer I wrote `irintf` myself (it calls `lrintf` and then checks if the result is in the `INT_MIN..INT_MAX` range; if not it raises Invalid FP exception and returns 0). – pmor Aug 07 '23 at 12:08
  • 1
    @pmor For clarity I meant "why did you use `lrint()` to convert a `float` and not `lrintf()`" and it is apparently you took the comment correctly like that. – chux - Reinstate Monica Aug 07 '23 at 19:25

2 Answers2

2

How to convert float to int according to the current rounding direction?

Create a helper function that calls lrintf() and add desired error handling per C spec: "If the rounded value is outside the range of the return type, the numeric result is unspecified and a domain error or range error may occur.".
I recommend against using irintf() in case that comes out later.

#incldue <errno.h>
#include <limits.h>

int my_irintf(float x) {
  long y = lrinf(x);
  // Add desired error handling here when int/long ranges differ.
  #if LONG_MAX > INT_MAX || LONG_MIN < INT_MIN 
    // Example
    if (y > INT_MAX || y < INT_MIN) { 
      errno = ERANGE;
      y = (y > INT_MAX) ? INT_MAX : INT_MIN;
    } 
  #endif
  return (int) y;
}

Some systems raise FE_INVALID like:

    if (y > INT_MAX || y < INT_MIN) { 
      fesetexcept(FE_INVALID);
      y = (y > INT_MAX) ? INT_MAX : INT_MIN;
    } 

Given implementation defined functionality with lrintf() on errors, my_irintf(float x) could benefit with likewise conditional code per implementation.


Why there is no version for int?

No strtoi() exists in the standard library either. I suspect for similar reasons.
See Why is there no strtoi in stdlib.h?.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

Maybe because int is quite small and you can easily write such a function yourself.

int irint(double x)
{
    #if (LONG_MAX > INT_MAX && LONG_MIN < INT_MIN)
    long result = lrint(x);
    #else
    long long result = llrint(x);
    #endif

    if(result > INT_MAX || result < INT_MIN) 
    {
        feraiseexcept(FE_INVALID);
        return 0;
    }
    return (int)result;
}
0___________
  • 60,014
  • 4
  • 34
  • 74