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