def polyfill_random(generator, size, dtype="float32", out=None):
    """Sample random floats from a generator in different numpy versions.

    Parameters
    ----------
    generator : numpy.random.Generator or numpy.random.RandomState
        The generator to sample from. Both ``RandomState`` and ``Generator``
        support ``random()``, but with different interfaces.

    size : int or tuple of ints, optional
        See :func:`numpy.random.Generator.random`.

    dtype : {str, dtype}, optional
        See :func:`numpy.random.Generator.random`.

    out : ndarray, optional
        See :func:`numpy.random.Generator.random`.


    Returns
    -------
    float or ndarray of floats
        See :func:`numpy.random.Generator.random`.

    """
    if hasattr(generator, "random_sample"):
        # note that numpy.random in <=1.16 supports random(), but
        # numpy.random.RandomState does not
        result = generator.random_sample(size=size).astype(dtype)
        if out is not None:
            assert out.dtype.name == result.dtype.name, (
                "Expected out array to have the same dtype as "
                "random_sample()'s result array. Got %s (out) and %s (result) "
                "instead." % (out.dtype.name, result.dtype.name))
            out[...] = result
        return result
    return generator.random(size=size, dtype=dtype, out=out)