+/*----- Default operations ------------------------------------------------*/
+
+/* --- @grand_defaultbyte@ --- *
+ *
+ * Arguments: @grand *r@ = pointet to generic generator
+ *
+ * Returns: A uniformly-distributed pseudorandom integer in the interval
+ * %$[0, 256)$%.
+ *
+ * Use: Default @byte@ output method. This calls the @range@ method
+ * to return a uniform random value between 0 and 255.
+ */
+
+octet grand_defaultbyte(grand *r)
+ { return (r->ops->range(r, 256)); }
+
+/* --- @grand_defaultword@ --- *
+ *
+ * Arguments: @grand *r@ = pointet to generic generator
+ *
+ * Returns: A uniformly-distributed pseudorandom integer in the interval
+ * %$[0, 2^{32})$%.
+ *
+ * Use: Default @word@ output method. This calls the @fill@ method
+ * to fill a 4-octet buffer with uniform random bytes, and then
+ * converts them to an integer.
+ */
+
+uint32 grand_defaultword(grand *r)
+ { octet buf[4]; r->ops->fill(r, buf, sizeof(buf)); return (LOAD32(buf)); }
+
+/* --- @grand_defaultrange@ --- *
+ *
+ * Arguments: @grand *r@ = pointet to generic generator
+ * @uint32 l@ = limit for acceptable results
+ *
+ * Returns: A uniformly-distributed pseudorandom integer in the interval
+ * %$[0, l)$%.
+ *
+ * Use: Default @range@ output method. This falls back to either
+ * @word@ (if the generator's @max@ is zero, or if @max < l@) or
+ * @raw@ (otherwise). This might recurse via @fill@ and @byte@,
+ * but this is safe because of the constraint on the @raw@
+ * method.
+ */
+
+uint32 grand_defaultrange(grand *r, uint32 l)
+{
+ uint32 m, z;
+ uint32 (*w)(grand */*r*/);
+ uint32 x;
+
+ /* --- Decide where to get data from --- *
+ *
+ * The choice of %$2^{32} - 1$% as a limit when using @grand_word@ isn't
+ * wonderful, but working with %$2^{32}$% is awkward and the loss of a few
+ * return values isn't significant. The algorithm below still successfully
+ * returns uniformly distributed results.
+ *
+ * If there's a raw generator, and it can cope with the limit, then use it;
+ * otherwise use the @word@ generator, which may recurse via @fill@ and
+ * @byte@, but by that point it must be able to satisfy us.
+ */
+
+ assert(l);
+ if (r->ops->max && r->ops->max >= l) {
+ w = r->ops->raw;
+ m = r->ops->max;
+ } else {
+ assert(!r->ops->max || r->ops->max >= 256);
+ w = grand_word;
+ m = 0xffffffff;
+ }
+
+ /* --- Work out maximum acceptable return value --- *
+ *
+ * This will be the highest multiple of @l@ less than @m@.
+ */
+
+ z = m - m%l;
+
+ /* --- Generate numbers until something acceptable is found --- *
+ *
+ * This will require an expected number of attempts less than 2.
+ */
+
+ do x = w(r); while (x >= z);
+ return (x%l);
+}
+
+/* --- @grand_defaultfill@ --- *
+ *
+ * Arguments: @grand *r@ = pointet to generic generator
+ * @void *p@ = pointer to a buffer
+ * @size_t sz@ = size of the buffer
+ *
+ * Returns: ---
+ *
+ * Use: Fills a buffer with uniformly distributed pseudorandom bytes.
+ * This calls the @byte@ method repeatedly to fill in the output
+ * buffer.
+ */
+
+void grand_defaultfill(grand *r, void *p, size_t sz)
+ { octet *q = p; while (sz--) *q++ = r->ops->byte(r); }
+