2

The modf() family of functions all take a pointer parameter:

float       modff( float arg, float* iptr );
double      modf( double arg, double* iptr );
long double modfl( long double arg, long double* iptr );

for returning the integral part of their input arg (the fractional part is the actual return value).

If I only need the fractional part, can I "skip" the computation of the integral part by passing NULL?

Neither the cppreference page I liked to, nor man modff, say anything about what happens when you pass NULL for iptr, while some other standard library functions take NULL as an indication of "ignore this parameter".

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 1
    "Can I "skip" the computation of the integral part by passing NULL?" --> Note that a good compiler could analyze inside `modf()` and see `ipart` in part is not used in `double foo(double x) { double ipart; return modf(x, &ipart); }` and emit efficient code that "skips" the computation of the integral part. – chux - Reinstate Monica Jan 05 '21 at 12:26
  • @chux-ReinstateMonica: That would require link-time optimization, as the code for `modf()` is already compiled, typically. – einpoklum Jan 05 '21 at 13:35
  • 2
    einpoklum, C allows the compiler to understand standard library functions and create equivalent code which, in this case, could optimize out any extra code not needed to get just the integer part. – chux - Reinstate Monica Jan 05 '21 at 14:39
  • @chux-ReinstateMonica: And does this actually happen for `modf()` I wonder... – einpoklum Jan 05 '21 at 15:41
  • 1
    Each year, I am surprised to find out how more intelligent compilers are able to optimize code. So if you do not see it this year, maybe later. – chux - Reinstate Monica Jan 05 '21 at 15:46
  • @chux-ReinstateMonica, that requires that `modf` be inlined by the compiler, which is not the general case. I agree that gcc takes `modf` family as builtins, but the thing is that they could be functions implemented as normal functions (compiled separately) because they are not part of libgcc, but part of libc. In that case, and in general, the compiler cannot assume much from how the functions are implemented internally, it is more a question related with the behaviour of `modf`. – Luis Colorado Jan 06 '21 at 00:30
  • @LuisColorado It does not require that `modf` be inlined. It is sufficient that the compiler can assume that function `modf()` is compliant and then use equivalent in-line code without calling the function `modf()`. This is fairly common with `sqrt()`. – chux - Reinstate Monica Jan 06 '21 at 03:34
  • Nope... it requires that the compiler knows the internals of the target function. This is done in gcc (or clang) only, and with extensions that are far to be standard, that indicate restrictions on the functions in order for the compiler to know that it can apply some optimizations. In general, for a separately compiled function there's nothing the compiler can do to rewrite the function internals and do what is requested by the PO. I used `inline` as an example, but the standard itself uses the `inline` concept as a hint and leaves freedom to the implementation to implement it as it wants. – Luis Colorado Jan 06 '21 at 04:23
  • the concept you are talking about is a gcc extension and the functions that it knows about are called _builtin functions_. That is not a general case that can apply to any user portable function. – Luis Colorado Jan 06 '21 at 04:25
  • and remember that `modf` is not a `libgcc` function, but a `libc` one (and gcc doesn't require to work with `libc`, it's a separate product) – Luis Colorado Jan 06 '21 at 04:27
  • What reference / man page would lead you to think this is even an option?? At best, the function might have something like gcc attributes `const` or `pure`. – Brett Hale Jan 06 '21 at 12:55
  • @BrettHale: Were you asking me, or replying to another comment? Also, what did you refer to as "this"? – einpoklum Jan 06 '21 at 12:57
  • @BrettHale: Well, my reputation almost doubled recently due to the question rep rising to 10 per point, so that's a bit misleading. If you look at my profile you'll see I ask a lot (sometimes answering myself). Anyway, I'll edit the question to clarify why I asked here. – einpoklum Jan 06 '21 at 13:09
  • @einpoklum - ok... I apologise. but this is like asking: 'what if I pass an illegal, arbitrary address to a function that expects a pointer to something'. Best case: pass the address of an 'integral' result on the *stack*. – Brett Hale Jan 06 '21 at 13:27
  • @LuisColorado *it requires that the compiler knows the internals of the target function* What do you base that on? It seems to be contradicted by [**5.1.2.3 Program execution**, paragraph 1](https://port70.net/~nsz/c/c11/n1570.html#5.1.2.3p1): "The semantic descriptions in this International Standard describe the behavior of an abstract machine in which issues of optimization are irrelevant." Given the way floating point values are defined, it seems "break[ing] the argument value into integral and fractional parts" would have zero side effects, so eliding the call seems allowable to me. – Andrew Henle Jan 06 '21 at 13:41
  • Yes, what is know as a _builtin function_ by gcc!!! :) eliding the call and using `float f = val - (int) val;` suffices for me. And this is actually left to the compiler to optimize. – Luis Colorado Jan 08 '21 at 00:07

5 Answers5

2

The standard doesn't define this

Description

2 The modf functions break the argument value into integral and fractional parts, each of which has the same type and sign as the argument. They store the integral part (in floating-point format) in the object pointed to by iptr.

Returns

3 The modf functions return the signed fractional part of value.

so behaviour when passing NULL will be undefined. You may find some compiler which allows it but any code relying on this would not be portable (even between versions of the same compiler).

simonc
  • 41,632
  • 12
  • 85
  • 103
2

According to the ISO/IEC 9899:2017 draft:

F.10.3.12 The modf functions

...

...

3 modf behaves as though implemented by

    #include<math.h>
    #include<fenv.h>
    #pragma STDC FENV_ACCESS ON
    double modf(doublevalue,double*iptr){
        intsave_round =fegetround();
        fesetround(FE_TOWARDZERO);
        *iptr =nearbyint(value);
        fesetround(save_round);
        return copysign(isinf(value) ? 0.0:value - (*iptr), value);
    }

So, I would say that you can't.

Mark Benningfield
  • 2,800
  • 9
  • 31
  • 31
  • 1
    That appendix is _informative_, so it provides insights, but is not spec. – chux - Reinstate Monica Jan 05 '21 at 14:42
  • @chux-ReinstateMonica Yes, I know. Also note that the cited source is the free draft copy, not the actual (expensive) latest standard. That's why I didn't want to positively assert that it wasn't possible. It wouldn't surprise me if there were an implementation out there that only writes to the pointer from inside a guard. – Mark Benningfield Jan 05 '21 at 15:26
  • ... and the standard is, itself, a normative _recommendation_. Compilers are free to implement a standard or not. It is the case that when a standard makes a non-normative hint about how to implement things, almost all the implementations do implement it as recommended. – Luis Colorado Jan 06 '21 at 00:34
2

As others answers suggest, you can't pass NULL - or at least, you can't rely on being able to pass NULL.

Instead, use something like this:

inline float fractional_part_float( float arg ) {
    float integral_part;
    return modff(arg, &integral_part);
}

and similarly for double and long double.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
2

Can I pass NULL to modf/modff?

modf(double arg, double* iptr) and friends lack defined functionality when iptr == NULL. Passing a NULL is undefined behavior (UB).

If code wants a one liner that does not need to save the integer part for later use, consider a compound literal for the temporary double and trust the compiler to optimize as able.

#include <math.h>

double fraction(double x) {
  return modf(x, &(double){0});
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • @einpoklum This does repeat a portion of others, yet it adds a direct alterative: form a compound literal and use its address. C has 2 literals, string and compound. Both of which can have their address taken. In the case of a compound literal, its contents can get changed. Writing to a string literal is UB. – chux - Reinstate Monica Jan 05 '21 at 15:43
  • 1
    @einpoklum Perhaps. Yet _compound literals_ are [very useful](https://stackoverflow.com/a/34641674/2410359) for temporary space. – chux - Reinstate Monica Jan 05 '21 at 15:55
  • Well [the compilation result seems to be the same](https://godbolt.org/z/xfTfr8), while your suggestion requires knowing an obscure language feature to even read. To you, as more of a guru, that might not be a problem, but others will find it difficult. The benefit is is that it takes one less line of code. Not sure it's worth it. Still, these compound literals are indeed a very useful trick. Thanks :-) – einpoklum Jan 06 '21 at 13:03
  • @einpoklum _Compound literals_ are not so much an obscure feature as a newish one since C99. I find it is slowly making it way into C introductory courses. C is a 40+ year old language and much inertia exist. If one prefers a more C89 experience, go ahead. As with such issues approaching style, code to your group's standard. – chux - Reinstate Monica Jan 06 '21 at 15:20
1

Man pages do not mention this way of using the function and if we look at the glibc implementation, it definitely doesn't have handling for that case:

https://code.woboq.org/userspace/glibc/sysdeps/ieee754/dbl-64/wordsize-64/s_modf.c.html

So no, that's not a thing you can legally do.

Also all that C99 has to say about modf is:

The modf functions break the argument value into integral and fractional parts, each of which has the same type and sign as the argument. They store the integral part (in floating-point format) in the object pointed to by iptr.

so the glibc implementation is perfectly fine in its conformance to the standard.