That section seems to invite undefined behaviour through (int)r != r  where
the integral part of r could exceed the representable part. The impact is
relatively small as the function ordinarily errors out under such
conditions, and the documentation is clear that this function is a footgun,
but UB is UB, and it seems like an uncharacteristic blemish rather than a
feature.

R core probably has existing and better inline functions machinery for
this, but data.table has the following to test whether (int)x is safe,
which I wrote:

```c
bool within_int32_repres(double x) {
  // N.B. (int)2147483647.99 is not undefined behaviour since s 6.3.1.4 of
the C
  // standard states that behaviour is undefined only if the integral part
of a
  // finite value of standard floating type cannot be represented.
  // Also, note that these are not the same values you would get from
INT32_MAX and INT32_MIN
  return R_FINITE(x) && x < 2147483648 && x > -2147483648;
}
```
so
 if (!R_FINITE(r) || (double)((int) r) != r) {
would become
 if (!within_int32_repres(r) || (double)((int) r) != r) {


On Tue, 12 May 2026 at 21:05, Tomek Gieorgijewski <[email protected]>
wrote:

> Hi!
>
> My first thought was that it may be possible as there is already coercion
> for numeric vectors to int if some conditions ("exactlyInteger")
> are met. Here is the code of Internal sprintf in that matter:
>  case 'x':
>  case 'X':
>           if(TYPEOF(_this) == REALSXP) {
>               // qdapTools manages to call this with NaN
>               Rboolean exactlyInteger = TRUE;
>               R_xlen_t i = 0;
>               R_xlen_t n = XLENGTH(_this);
>               for(i = 0; i < n; i++) {
>                   double r = REAL(_this)[i];
>                   if (R_IsNA(r)) continue; // NA_REAL is ok
>                   if (!R_FINITE(r) || (double)((int) r) != r) {
>                       exactlyInteger = FALSE;
>                       break;
>                   }
>                }
>               if(exactlyInteger)
>               _this = coerceVector(_this, INTSXP);
>                PROTECT(a[nthis] = _this);
>                nprotect++;
>            }
>          break;
>
> But the idea here is to coerce to INTSXP and then do formatting, so it
> won't store bigger integers than 31 bits.
> And without coercion we may need to wait for 64bit integers in R or change
> the further part of the code for
> REALSXP where we add separate part for "%x" format and check if it's pure
> integer stored in numeric:
> case REALSXP:
>                               {
>                                   double x = REAL(_this)[ns % thislen];
>                                   if (checkfmt(fmtp, "aAfeEgG"))
>                                       error(_("invalid format '%s'; %s"),
> fmtp,
>                                             _("use format %f, %e, %g or %a
> for numeric objects"));
>                                  if (R_FINITE(x)) {
>                                      _my_sprintf(x)
>                                   } else { // ....and so on
> I guess changing _my_sprintf macro would also be involved as it is based on
> snprintf and generally "%x" format does not allow double/floats.
> But that's only my first attempt at analyzing sprintf function. The file
> sprintf.c has ~500 lines of code and even more subtleties one must
> understand to change the function.
>
> So if you really need bigger ints to be shown as hex, I propose you
> implement your own R function to print such thing.
> Start with dividing by 16 iteratively and checking the modulo for proper
> hex character.
>
> T.
>
> wt., 12 maj 2026 o 09:38 Sokol Serguei via R-devel <[email protected]>
> napisaƂ(a):
>
> > Hi,
> >
> > I wanted to print a big integer value in hexadecimal format with
> sprintf()
> > but could not (cf. here
> > after). As R supports integer values upto 2**53-1 (storing them in a
> > double) is it possible to make
> > sprintf() to work on such big values?
> >
> > Best,
> > Serguei.
> >
> >  > sprintf("%x", 2**31-1)
> > [1] "7fffffff"
> >  > sprintf("%x", 2**31)
> > Error in sprintf("%x", 2^31) :
> >    invalid format '%x'; use format %f, %e, %g or %a for numeric objects
> >  > sessionInfo()
> > R version 4.6.0 (2026-04-24)
> > Platform: x86_64-pc-linux-gnu
> > Running under: Linux Mint 21.1
> >
> > Matrix products: default
> > BLAS/LAPACK: /opt/OpenBLAS/lib/
> libopenblas_nonthreaded_haswell-r0.3.27.so;
> > LAPACK version 3.12.0
> >
> > locale:
> > [1] C
> >
> > time zone: Europe/Paris
> > tzcode source: system (glibc)
> >
> > attached base packages:
> > [1] stats     graphics  grDevices utils     datasets  methods  base
> >
> > loaded via a namespace (and not attached):
> > [1] compiler_4.6.0
> >
> > ______________________________________________
> > [email protected] mailing list
> > https://stat.ethz.ch/mailman/listinfo/r-devel
> >
>
>         [[alternative HTML version deleted]]
>
> ______________________________________________
> [email protected] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

        [[alternative HTML version deleted]]

______________________________________________
[email protected] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to