Locale-independent float print function
Implementation simplicity
As code is incorrect in too many cases, simplicity assessment is moot.
Ability to be used on different sorts of streams (writing into a file, a string, etc)
Code assumes it can pass a void * like a FILE *.  Reasonable, but not specified by C.
Writing to a string deserves a size parameter.
Rather than attempt to use fprintf(), sprintf(), consider providing interface functions.
Reasonable corrrectness
corrrectness --&gt;  correctness
OP is brave.  Quality conversion of a string to a double is hard.
To assess, I set up a test harness.
void test(double x) {
  // Reference output
  printf(&quot;R%.*e %20a\n&quot;, DBL_DECIMAL_DIG - 1, x, x);
  // OP's output
  printf(&quot;&lt;&quot;);
  print_number((printfn_t) fprintf, stdout, x);
  puts(&quot;&gt;\n&quot;);
}

int main(void) {
  const double x[] = {1.0, 1.0 / 7, DBL_MIN, DBL_TRUE_MIN, DBL_MAX, INFINITY,
      NAN, -DBL_MAX, -0.0, 1.0 + DBL_EPSILON, 1.0 - DBL_EPSILON};
  size_t n = sizeof x / sizeof *x;
  for (size_t i = 0; i &lt; n; i++) {
    test(x[i]);
  }
}

Outright discrepancies included
R4.9406564584124654e-324            0x1p-1074
&lt;0.-9223372036854775808e-324&gt;                          ???

Rinf                  inf
&lt;-9223372036854775808.-9223372036854775808e2147483647&gt; ???

Rnan                  nan
&lt;-9223372036854775808.-9223372036854775808&gt;            ???

R-0.0000000000000000e+00              -0x0p+0
&lt;0&gt;                                                    Missing sign

R9.9999999999999978e-01 0x1.ffffffffffffep-1
&lt;0.1000000000000000&gt;                                   Off by 10x!

Non-finite
For NAN and infinity, consider a !isfinite(x) test and then handle those special cases.
Sign
For -0.0 correctness,
//if (number &lt; 0) {
if (signbit(number)) {
    print(&quot;-&quot;);
    ...

Precision
double deserves up to DBL_DECIMAL_DIG (e.g. 17) places of output to properly distinguish all double from other double.  OP's precisions output wobbles with inconsistent significant precision output.
I adjusted OP's code to int PRECISION = DBL_DECIMAL_DIG;, then used select values like 1.0 - DBL_EPSILON (and many others) are not quite correct.
R9.9999999999999978e-01 0x1.ffffffffffffep-1
&lt;0.99999999999999984&gt;

As a reference, to print the exact value of a finite double. See Function to print a double - exactly
Numeric correctness.
Each *, / and some pow(10, ) inject 0.5 [ULP] or more error into the math and there is little code compensating for these accumulating errors.  Without internal extended math, I see OP's approach as unable to achieve a high quality result.
Code assumes double precision &lt; 64 bits.  Reasonable, but not specified by C.

Recommendation
Test with the usual suspects as in the test harness, with values near powers of 10 and with various random values.