[Question]
  [
Given a number \$n ‚â• 2\$, a [blackbox function](https://codegolf.meta.stackexchange.com/a/13706/100664) \$f\$ that takes no arguments and returns a random integer in the range 0...n-1 inclusive, and a number \$m ‚â• n\$, your challenge is to generate a random integer in the range 0...m-1 inclusive. You may not use any nondeterministic builtins or behaviour, your only source of randomisation is \$f\$.
The number you produce must be uniformly random. \$m\$ is not limited to powers of \$n\$.
One way to do this could be to generate \$\operatorname{ceil}(\log\_n(m))\$ random numbers, convert these from base \$n\$ to an integer, and reject-and-try-again if the result's greater than or equal to \$m\$. For example, the following JS could do this:
```
function generate(n,m,f){
  let amountToGenerate = Math.ceil(Math.log(m)/Math.log(n)) // Calculating the amount of times we need to call f
  let sumSoFar = 0;        
  for(let i = 0; i < amountToGenerate; i++){  // Repeat that many times...
    sumSoFar *= n;            // Multiply the cumulative sum by n
    sumSoFar += f()           // And add a random number
  } 
  if(sumSoFar >= m){          // If it's too big, try again
    return generate(n,m,f); 
  } else {                    // Else return the number regenerated
    return sumSoFar
  }
}
```
An *invalid* solution could look something like this:
```
function generate(n,m,f){
  let sumSoFar = 0;
  for(let i = 0; i < m/n; i++){ // m/n times...
    sumSoFar += f()             // add a random number to the cumulative sum
  }
  return sumSoFar
}
```
This is invalid because it takes the sum of \$\frac{m}{n}\$ calls of f, so the randomness is not uniform, as higher/lower numbers have a smaller chance of being returned.
\$f\$ is guranteed to produce uniformly random integers, and can be independently sampled as many times as you want.
Instead of taking \$f\$ as a function, you may also take it as a stream or iterator of values, or an arbitrarily long list of values. The ranges may be 1...n instead of 0...n-1.
## Scoring
This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), shortest wins!
  
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~6~~ 5 bytes
```
√á√ê·πÄ·∏ä¬ø
```
[Try it online!](https://tio.run/##AR0A4v9qZWxsef81WOKAmf/Dh8OQ4bmA4biKwr////8yNw "Jelly ‚Äì Try It Online")
A monadic link taking `m` as its argument and expecting the blackbox function to be in the previous link (e.g. header on TIO). Thanks to @JonathanAllan for pointing this out as per [this meta post](https://codegolf.meta.stackexchange.com/a/13707/53748) and also for saving a byte with a suggested switch to 1 indexing!
## Explanation
```
      | Implicit range 1..m
   ·∏ä¬ø | While list length > 1 (literally while the list with its first member removed is non-empty):
 √ê·πÄ   | - Take the list member(s) that are maximal when:
√á     |   - The supplied function is run for each list member
```
---
If the function had to be provided as an argument, here is an alternative:
# [Jelly](https://github.com/DennisMitchell/jelly), 8 bytes
```
·πõ‚Å¥V$√ê·πÄ·∏ä¬ø
```
[Try it online!](https://tio.run/##ASQA2/9qZWxsef//4bmb4oG0ViTDkOG5gOG4isK/////Mjf/NVjigJk "Jelly ‚Äì Try It Online")
A full program taking `m` and the Jelly code for `f` as its two arguments. If it‚Äôs mandatory to also take `n`, this can be provided as an (unused) third argument.
## Explanation
```
          | Implicit range 1..m
       ·∏ä¬ø | While list length > 1 (literally while the list with its first member removed is non-empty):
    $√ê·πÄ   | - Take the list member(s) that are maximal when:
 ·πõ‚Å¥V      |   - The supplied function is run for each list member
```
---
# Previous answer: [Jelly](https://github.com/DennisMitchell/jelly), 16 bytes
```
¬≥lƒä‚ÅµV¬§‚Ç¨·∏Ö ã‚Å¥¬§<¬≥¬¨$¬ø
```
[Try it online!](https://tio.run/##ATQAy/9qZWxsef//wrNsxIrigbVWwqTigqzhuIXKi@KBtMKkPMKzwqwkwr////83Mv84/zhY4oCZ "Jelly ‚Äì Try It Online")
A full program that takes `n`, `m` and the Jelly code for `f` as its arguments and prints the resulting random number to STDOUT.
## Explanation
```
           <¬≥¬¨$¬ø | While not < m:
¬≥        ã‚Å¥¬§      | - Do the following, taking m as the left argument and n as the right:
 l               |   - m log n
  ƒä              |   - Ceiling
   ‚ÅµV¬§‚Ç¨          |   - Execute f that many times
       ·∏Ö         |   - Convert from base n
```
[Answer]
# [Wolfram Language (Mathematica)](https://www.wolfram.com/wolframscript/), ~~40~~ 39 bytes
```
r&@While@!(r=Nest[nÔí°n#3+#2[],0,#])<#&
```
[Try it online!](https://tio.run/##y00syUjNTSzJTE78n2b7v0jNITwjMyfVQVGjyNYvtbgkOu/9pIV5ysbaykbRsToGOsqxmjbKav8DijLzSvQdgvOLShxCEnNyKoFkUk5qdFq0uY5CUGJeSn6uZ15JanpqkUO1gY5RrZqOgnGsjoKhARDE/gcA "Wolfram Language (Mathematica) ‚Äì Try It Online")
Input `[m, f, n]`. Interprets `m` random digits in base `n` until the result is in `[0, m)`.
[Answer]
# [J](http://jsoftware.com/), 37 32 26 bytes
```
1 :'$:@[`]@.(=&#)I.@:u@$~'
```
[Try it online!](https://tio.run/##HctBC4IwAIbhu7/iy6Qp2UjEwIE0CoIgOnQNIZMtS3OxadKlv76kw3t54H3YdMKifDVhKSGOS4lExkAQYgk2tqDYng47G4ERj/HzJefUz2bTYE8567n3JTZwjhsK9RZaNmowMF1R1pBKoyn0TWjc21ffmRDXvsOgdG1GQVcJpT//tc3iEM8scURZKfhrHrtzyAAJ7A8 "J ‚Äì Try It Online")
-6 bytes thanks to xnor's suggested method.
Will overflow the stack for larger inputs since it recurses, but works in theory.
# base-n method, modified, 37 32 bytes
```
1 :'([#.u@#~)/@[^:(]>:1{[)^:_&_'
```
[Try it online!](https://tio.run/##y/pvqWhlGGumaGWprs6lpKeepmBrpaCuoKNgoGAFxLp6Cs5BPm7/DRWs1DWilfVKHZTrNPUdouOsNGLtrAyrozXjrOLV4tX/a3JxpSZn5Cto2DuYKmkrpGkqmCoYGv0HAA "J ‚Äì Try It Online")
Uses suggested method, except instead of taking the log first just generates m random base-n digits. This makes it *much* slower, but saves 5 bytes.
The solution is a J adverb, which modifies the black box function, and takes `n` as the left arg and `m` as the right arg.
# base n method, fast, 37 bytes
```
1 :'([#.>.@^.u@#[)/@[^:(]>:1{[)^:_&_'
```
[Try it online!](https://tio.run/##y/pvqWhlGGumaGWprs6lpKeepmBrpaCuoKNgoGAFxLp6Cs5BPm7/DRWs1DWilfXs9Bzi9EodlKM19R2i46w0Yu2sDKujNeOs4tXi1f9rcnGlJmfkK2jYO5gqaSukaSqYKhga/QcA "J ‚Äì Try It Online")
[Answer]
# [Husk](https://github.com/barbuz/Husk), ~~17~~ ~~15~~ 13 bytes
*Thanks to xnor for the inspiration for the method: here it's taken to an even-more-inefficient extreme by repeatedly generating `m` random numbers until all except one are zero, and the only non-zero one is 1*
```
‚Ç¨1·∏üo=1Œ£Cm`%‚ÇÅ‚àû
```
[Try it online!](https://tio.run/##jZo7rlNBEEQ3RFAVERGxDESORECA2AAbISBlAayCPcBGLgTo6XrmnB7LepblN/bM9Ke6utofvnz@eF1/vv7o75/fPr3pr@9vr@t611d5efT/c19e3f96@9@6cv10b69sxX2fPuzT24657ZeX1YET3vd43I/WZTnB/pn9ZFnuxt9TeM7DfVZ7drlbFns8nqryXeuJ93UZTtZtT4qHihd2e7D1gl4u3GQ9YzZfPVpujZT9ZrSu2/d1ifHAu6tPba/ijbPE0nrPoH3M@kULkh0n35L/i7kajceTVeezZ7QBx/OemVW8yJbnnF3k8TWi6TP2KGDKnsMdkMdutr@3Ry6vo1taZpLFCvnIp80ByyNWLMY9nZMiIRtCr/7o5psqQkdtwBVhz49nUJZRxe6zoxTVlUDkUt7P1YqQPFA73e@FeuyY4llH2Bu1P9fuIi4zEtJ6Q5QOHKUQ3YEo6VYZKD8YeXZv7jGTIa7pVGyFSPZkqD9BzhfFr/U7KFaDXvAMLOJiDhgRzMiijck3xNAy@v/EjCvct2N8Gg82PKA4yFjXA5ESwPBqjSlw3L2qkNcoUrp5svI8115bZTFiDJaZ3FwLK54tsMdi1XNeF7HoxE2IM/CNK7HXoUZXqnsEZYKMMcNtjOcEeHhHHuv80SKW84f6lgmXJgZmvUOV4T6Dg5FqZ5zBMqBQ26p1zNmTVTKL/AA@Gg@3bCxizcxzrBd2BPeOKaKpdODztEeHTrpHxYN7QqttXj9NA@mB6xWZUTFmT319MZYjOkv0pFEFid/PoDEwIjpXCHQBOdhs4l@eb9xxROKygoEFlOTorGhGpxoTUc2qeep@zaE7DOZbxt6F9DLngVN3RzE8s2nmqhHlxjslR0qukdEOclKjqFJ4BWCmYapPUNfmfq5PaMMTknRgNoZLxRhkJhXtwjoifEe9KwdGVFAAKpymoq@zMtRBISaNKFgX8pT@aVykgx/OkeHKSw/qeIWxGj@vIMAc86SWWE3K0HdG7FDsxElJM@Xa@ITrgVUlMapq@/nsNK7oz2rNpMCapphhHuOqhPcXGaw9M1SbxnC@Ftmvzbd6mKUYZpht5ymDVasqY4ngljP2KnP0HPUu1bhyB2YduQFpTD1Mz6xnNi23wr4srjMqIx30qBymy5GZTYf6x3GdYQJbVU0mDcS1TMOUDF4NRibPkXM4dUWh6aEfdKSzWVkP3VxFv6wytqgmbx1Gtcc/q8pVXWCaF0zImpEr5qBwT9N5nlu6/mO28q7d@lPXdqa5sjEpV20ryBztDk6/eqlMmXLQAHyqyuhV1XA69Kdzp2DYVJ2KuOJhmDf/XsSncBnZZZ/@xYxpfFHUj9QHq4BeHTNoQoy6Ns01znCyn09BirkVqbmGg6ytRSp6Diwzh99MVb01oZAr7vNEqKrq/Hv1/nr9Fw "Husk ‚Äì Try It Online")
[Husk](https://github.com/barbuz/Husk) is usually rather badly-suited for challenges involving randomness, since it has no built-in random number generator.
So it's very welcome to have a challenge where a random number generator is assumed as a black-box function!
In this case, the black-box random number function is assumed to be located on line 2 (called using the [Husk](https://github.com/barbuz/Husk) command "`‚ÇÅ`").  
However, obviously, without actually having this function it's tricky to test the code, so the TIO link substitutes the last few bytes `m`%‚ÇÅ‚àû` and input `n` for a pre-generated-by-me list of random integers between zero and one (so `n` equals 2).
```
             ‚àû       # infinitely repeat arg1;
         m           # now, for each element n of this list
          `%‚ÇÅ        # call black-box function ‚ÇÅ, and return the result modulo n;
        C            # now cut this infinite list into sublists of length m = arg2
  ·∏üo                 # Return the first sublist for which
      Œ£              # the sum
    =1               # is  equal to 1;
‚Ç¨1                   # what's the index of 1 in this sublist?
```
Note: the `m`%‚ÇÅ‚àû` construction to get the infinite list of random numbers might seem (and is) a bit clunky.
This is because (I think), not having any non-deterministic functinos, [Husk](https://github.com/barbuz/Husk) doesn't have or normally need a higher-order function that will repeat a particular function *that takes no arguments*.  
Luckily in this case, we know that the output of our black-box function is unchanged modulo `n`, so we can 'use-up' an argument without changing the output.  
[Here's a Try it online link](https://tio.run/##yygtzv7/PzdB9VFT46OOeVzm////NzQAAA) to the `m`%‚ÇÅ‚àû` bit on its own, here with a function on line 2 that simply returns the number `7` each time it's called. Try to pretend that this is a random number...
[Answer]
# [R](https://www.r-project.org/), ~~70~~ ~~69~~ 62 bytes
**(or [R](https://www.r-project.org/)>4.1, ~~56~~ 55 bytes)**
*Edit: -7 bytes thanks to pajonk*
```
function(m,f){while(sum(F)!=1)for(i in 1:m)F[i]=!f();which(F)}
```
[Try it online!](https://tio.run/##TY5BCoMwFET3OcUvbvLBQlNwY8nWS5Quoib4qYkSE6QVz24jLdJZDsOb57dJ2bHXVm4muibQ4LjNDS5zR73mU7S8wpMUaAbPCciBKC1Wd3rIk@F4S7OmS5N1c/LKjDwguHzB3OUCz2Jlvx9eJDpk4JVrBwsu2lp7qHWYtU5wSDUUjGXQdLp5QuhUgJam4KmOOxhogugo6diSBVXvkmoc@xcXpbik5IfCG/8/EbcP "R ‚Äì Try It Online")
Port of ~~[my Husk answer](https://codegolf.stackexchange.com/a/233806/95126)~~ xnor's approach. Keeps generating sequences of `m` random numbers until we get one that contains a single `0`: then we output the position of the `0`. Obviously this is not very efficient, but at least its significantly better than waiting for sequences of all zeros with a single `1` (previous version)...
As explained by Nick Kennedy in [his R answer](https://codegolf.stackexchange.com/a/233809/95126), R] version >4.1 lets us exchange "`function`" for "`\`" to save 7 bytes, but unfortunately we can't link to it on TIO or rdrr.io (yet).
[Answer]
# [Japt](https://github.com/ETHproductions/japt), ~~12~~ 10 [bytes](https://en.wikipedia.org/wiki/ISO/IEC_8859-1)
Based on xnor's suggested method in the challenge comments. Takes `m` as the first input `n` as the second and [assigns `f` to variable `W`](https://codegolf.meta.stackexchange.com/a/13707/53748). Outputs a singleton array
```
√à√ä√â}f@oW √∞
```
[Try it](https://petershaggynoble.github.io/Japt-Interpreter/?v=1.4.6&header=OAo1CkBW9g&code=yMrJfWZAb1cg8A&input=LVE) or [check the distribution over 1000 runs](https://petershaggynoble.github.io/Japt-Interpreter/?v=1.4.6&header=OAo1CntW9g&code=QbPGyMrJfWZAb1cg8MPOw/wgrs4rIjoge1rKL0EgeDEg%2bTR9JQ&input=LVI) (warning: may take a while to complete)  
*(All 3 inputs are taken in the header, where each line is assigned to one of Japt's input variables in order. The first line is `m`, the second `n` and the 3rd `f`. Doing this makes no difference to the main programme, saving no bytes; it's done purely to keep everything in one place for easier testing as functions cannot be taken as direct input by Japt.)*
## Black box function W
```
{V√∂     :Implicit input of integer V=n
{       :Function
 V√∂     :  Random int in [0,V)
```
## Main programme
```
√à√ä√â}f@oW √∞     :Implicit input of integer U=m
√à              :Left function, taking an array as argument
 √ä             :  Length
  √â            :  Subtract 1
   }           :End left function
    f          :Run the right function continuously, returning the first result that returns falsey (0) when passed through the left function
     @         :Right function
      o        :  Range [0,U)
       W       :  Run each through W
         √∞     :  0-based indices of truthy (non-zero) elements
```
[Answer]
# [Haskell](https://www.haskell.org/), ~~49~~ 47 bytes
```
m!l|[x]<-[x|(x,1)<-zip[1..m]l]=x|1>0=m!drop m l
```
[Try it online!](https://tio.run/##y0gszk7Nyfn/P1cxpya6ItZGN7qiRqNCx1DTRrcqsyDaUE8vNzYn1raixtDOwDZXMaUov0AhVyHnf25iZp5tQVFmXomKqWK0oY6hjhEYo0JDdHbsfwA "Haskell ‚Äì Try It Online")
Implements [xnor's algorithm](https://codegolf.stackexchange.com/questions/233790/adaptive-randomisation#comment533500_233790)
> 
> Make a list of \$m\$ outputs from \$f\$, if it has a single \$0\$ output its position, otherwise retry.
> 
> 
> 
However we don't need to make a list since we take a list as the input.
We also use \$1\dots n\$ ranges because it saves us 2 bytes.
[Answer]
# [Python 3.8 (pre-release)](https://docs.python.org/3.8/), 72 bytes
```
f=lambda m,g:(l:=[g()for x in"1"*m]).count(1)==1and-~l.index(1)or f(m,g)
```
[Try it online!](https://tio.run/##LY3dCsIwDEbv@xRlV82YY0EEKfRJhki1ay2sP5QK88ZXrxkuEAIf5@TLn/pK8XzNpdmSAi86Gjo@5FRqz5xadXgYLfec1i0CB5yABYUXFhViswfCw@CkWKWanQCbCt@4jx12fbjB@EzvWAWCUkiPTt919NEsGyUEWkEqtN25k8OPnokGZC6ezD8C7Qc "Python 3.8 (pre-release) ‚Äì Try It Online")
Uses @xnor's method
-6 and fix thanks to @ovs
Generates the blackbox function for m times, and try to pick the index of 0 from it, if not present recurse.
Looks like the relevant function Dosen't need to take n at all, because it is hardcoded inside g()
Also it is needed to check if list has only one zero, so the choosing remains uniform
[Answer]
# [R](https://www.r-project.org/) >= 4.1, ~~67~~ 64 bytes
```
\(m,f,x=1:m){while(x-max(x))x=x[max(y<-sapply(x,\(z)f()))==y];x}
```
[Try it online!](https://tio.run/##K/qfbvs/rTQvuSQzP08jVydNp8LW0CpXs7o8IzMnVaNCNzexQqNCU7PCtiIaxKy00S1OLCjIqdSo0IFrq9JM09DU1LS1rYy1rqj9n65hZI6Q1CxOzC0AGmWqY6ipa6j5HwA "R ‚Äì Try It Online")
An R translation of [my Jelly answer](https://codegolf.stackexchange.com/a/233794/42248). TIO link uses `function` in place of `\` since TIO isn‚Äôt on R 4.1 yet.
Thanks to @DominicVanEssen for saving 3 bytes!
If it were permissible to require that the Blackbox function take a single unused argument, this would do for 61:
# [R](https://www.r-project.org/) >= 4.1, ~~64~~ 61 bytes
```
\(m,f,x=1:m){while(x-max(x))x=x[max(y<-sapply(x,f))==y];x}
```
[Try it online!](https://tio.run/##K/qfbvs/rTQvuSQzP08jVydNp8LW0CpXs7o8IzMnVaNCNzexQqNCU7PCtiIaxKy00S1OLCjIqdSo0EnT1LS1rYy1rqj9n65hZK4DN6ZKszgxtwCo3VTHUFPXUPM/AA "R ‚Äì Try It Online")
[Answer]
# [JavaScript (V8)](https://v8.dev/), ~~63~~ ~~61~~ 60 bytes
```
(m,f,r=(i=m,p)=>i?f()?r(i-1,p):p?r():r(i-1,i):p||r())=>r()-1
```
[Try it online!](https://tio.run/##JY5LDsIwDET3OYWXNv2oXYFa0p6AQ0TQlKAkrtKqG8rZgwVezMyTPZJfZjfrPbllq/ZLnnXGUNoyaXQ6lAvpwY0WaUzoqla4WyRS90cneBzCciZatTmChrMKom2jrBgS6AFuZnvW1jMn/MVk4oOD7E4QSVlOgH7awEmh6cWuUhcvCoK3Apk7x5X9VHuecZYPwRL16pO/ "JavaScript (V8) ‚Äì Try It Online")
Using xnor's method. The recursive function `r(i,p)` counts down from `i = m` while `i > 0`. If finds a zero `f()` it records position `i` as `p` except if there is already a `p` it restarts by calling `r()`. If `i` gets to zero and there is a `p` it returns `p-1` as the result otherwise it restarts.
[Answer]
# [Python 3.8 (pre-release)](https://docs.python.org/3.8/), 70 bytes
```
h=lambda m,n,f:h(m,n,f)if(s:=sum(n**k*f()for k in range(m)))>=m else s
```
[Try it online!](https://tio.run/##RYzNDsIgEITP8hR7ZEkPVC@GBF/FYApC2l0I1INPj60/8TCZZL6ZKc81Zj6dS@2hZoLqeNosUcl1VYLsqAXbowh2cXSbnNkLm@5eMvb4TYEGHoKJ8u2YgmzGtgdJVmpWQWLIFWZIDJ8pIeLFEvileWh9p9c/HbXWaMSh1MSr/J1ifwE "Python 3.8 (pre-release) ‚Äì Try It Online")
Generates a random number up to n^m (always larger than m) with n invocations of f, then retries if the result is >=m.
Blows up the stack for large n and m, because n^m is *much* larger than m.
[Answer]
# [Charcoal](https://github.com/somebody1234/Charcoal), 16 bytes
```
ÔºÆŒ∏Ôº∑‚äñ‚ÑñœÖ‚Å∞‚âîÔº•Œ∏ÔºÆœÖÔº©‚åïœÖ‚Å∞
```
[Try it online!](https://tio.run/##TYzBCsIwEETv@xU5biBCWm2q9CQVwYPiL8Q02ECbtmminx8XQZDhMbswM6bXwUx6yPni5xRvaXzYgAtv4N27wTI8WRPsaH20HbZT8hGTYJJzzo7r6p4er3rGRbD/OueCJZq4B0f5Vq8Rz853v2aTcyFhDzXsQBIFVKDoUuQl/TVJEYdvRpKXREWqiS2ovHkNHw "Charcoal ‚Äì Try It Online") Link is to verbose version of code. Uses the method @xor suggested in a comment to the question. Takes `m` and a stream of random integers as input. Explanation:
```
ÔºÆŒ∏
```
Input `m`.
```
Ôº∑‚äñ‚ÑñœÖ‚Å∞
```
Repeat until the predefined empty list contains exactly one zero.
```
‚âîÔº•Œ∏ÔºÆœÖ
```
Input `m` random integers to the predefined empty list.
```
Ôº©‚åïœÖ‚Å∞
```
Output the position of the zero.
24 bytes for fastest code:
```
ÔºÆŒ∏ÔºÆŒ∑‚âîŒ∑Œ∂Ôº∑¬¨‚ÄπŒ∂Œ∑‚âî‚Ü®Ôº•‚Ü®‚äñŒ∑Œ∏ÔºÆŒ∏Œ∂Ôº©Œ∂
```
[Try it online!](https://tio.run/##TYzLCsIwEEX3@YosZyCCdduVj42gxV@IcTCBNG0zqUJ@PkYs2MUd7hkux1gdzaB9Kecwzqmb@ztFmLAVa7aV98zuGcAqmSu9rfMkoRsSXIgZspIWEeWyOmgmuOrxV05kIvUUEj2qSsmpZq3H5fcV36ILCY6aE2TEtpSdaLaiEf/UWzYv/wE "Charcoal ‚Äì Try It Online") Link is to verbose version of code. Takes input as a stream of random integers. Explanation:
```
ÔºÆŒ∏ÔºÆŒ∑
```
Input `n` and `m`.
```
‚âîŒ∑Œ∂
```
Start with `m` as the trial result (because we know it is too big).
```
Ôº∑¬¨‚ÄπŒ∂Œ∑
```
Repeat until a usable result is achieved.
```
‚âî‚Ü®Ôº•‚Ü®‚äñŒ∑Œ∏ÔºÆŒ∏Œ∂
```
Input the minimum number of random digits (obtained by converting `m-1` to base `n`) and convert that to base `n`.
```
Ôº©Œ∂
```
Output the final random integer.
[Answer]
# [APL(Dyalog Unicode)](https://dyalog.com), 19 bytes [SBCS](https://github.com/abrudz/SBCS)
Implements the algorithm suggested by xnor.
```
{‚ç∏1=‚àò‚ç∫‚ç∫¬®‚ç£{1=+/‚ç∫}‚ç≥‚çµ}
```
[Try it on APLgolf!](https://razetime.github.io/APLgolf/?h=AwA&c=q37Uu8PQ9lHHjEe9u4Do0IpHvYurDW219YGc2ke9mx/1bq0FAA&f=C84vKlF41DZB4VFX06OOGY96ux/1bH/UtYgrTyEXLG5ooGBkwJUOZlfb59VyPeroUg9KLS7NKVHIT1NX0PADyhgaAIGmgnpyYk5OsZU6VzDI1OpHvbt0HnUuetS7tfZRz47qR13N6QppCrm1h1Y86t3sBwA&i=AwA&r=tryapl&l=apl-dyalog&m=dfn&n=f)
The blackbox function is called with dummy arguments it ignores, which I think should be fine as there is no way to pass a niladic function to an operator.
`‚ç≥‚çµ` create a range from 1 to n
`¬®` for each value in the current list ...  
`‚ç∫‚ç∫` call the blackbox function ...  
`‚ç∏` get all indices of 1's in the resulting boolean mask. This returns a singleton value
3 bytes can be saved by using a full program instead of a *dop*, but this is quite inconvenient to use:
```
‚ç∏1=‚àò‚éï¬®‚ç£{1=+/‚ç∫}‚ç≥‚éï
```
[Try it on APLgolf!](https://razetime.github.io/APLgolf/?h=AwA&c=e9S7w9D2UceMR31TD6141Lu42tBWW/9R767aR72bgWIA&f=AwA&i=S@MyMuCqtjc0qAUA&r=tio&l=apl-dyalog&m=tradfn&n=f)
[Answer]
# [Ruby](https://www.ruby-lang.org/), 60 bytes
```
f=->n,g,m,r=0,z=1{z>m ?r<m ?r:f[n,g,m]:f[n,g,m,r*n+g[],z*n]}
```
[Try it online!](https://tio.run/##PYtBCsIwFET3niLUjdbfkip0ITYepGQRsS0B84lJIzUhZ49RqJvhMW/GuNs7pbGrGMIECkxHwXdN8EyRq7l84zz2P8dXAFPiYeo5@BJ5TJrkA6W0nqUabK2EDmPftBQqFozA@y7zPsKpOfK40W62pFBiIRUj2@DzfIlAXuLhBrt2DuWzttIP2SiJ/6nEWKQP "Ruby ‚Äì Try It Online")
Use the log() approach, with a recursive function: `z` is the maximum possible random number for a given iteration, `r` is the current accumulated value.
[Answer]
# [C (gcc)](https://gcc.gnu.org/), ~~76~~ \$\cdots\$ ~~70~~ 67 bytes
```
i;c;g(n,m,f)int(*f)();{for(;n;)for(n=i=m;i--;)!f()?n-=m,c=i:0;n=c;}
```
[Try it online!](https://tio.run/##1ZJRS8MwEIDf9yvOQiHZEuwUEXfG/RC3h5E2JWBu0lYUR/@69ZLWbbAHX3zxIEmP73L9EmJ1be0weLRYC1JBOempE3MnhcSD2zcCCWVcyXgT0GuN8soJuSZtgrLGrwokY7EfeB8QzuLSUCkkHKCpureGoNnFPCeEPuGw8xT5DDjaRDsfKlFIiRALuqrt6HkLBg73CpZLBTf9iYSRLG8ZRfzQY@rEliBikaey@uCSAqfPR2j9Z7V3IjWW11M2H1OExSLV/SjFIN4/aiS0xSNJJ5houKCvDXMnMjJ5CXxPoJ8gU8B/OZacPCdH9rsrksW5wXm3vM1L7uLXPGWrjOd0xWdN@wuDDdUiLxXE4Y4eCsJfq4wPh4V@89H/NTaUTUfrZ/3wZd3Lrm4H/f4N "C (gcc) ‚Äì Try It Online")
Saved 3 bytes thanks to [att](https://codegolf.stackexchange.com/users/81203/att)!!!
Uses [xnor](https://codegolf.stackexchange.com/users/20260/xnor)'s idea by repeatedly calling \$f()\$ \$m\$-times and if \$f()\$ returns \$0\$ once and only once, then returns the time (with \$0\$ being the last time and \$m-1\$ being the first) that \$f()\$ was \$0\$.
[Answer]
# [JavaScript (Node.js)](https://nodejs.org), 60 bytes
```
(n,f,m)=>(g=p=>p*m/d^-~p*m/d?g(p*n+f(),d*=n):p*m/d)(0n,d=1n)
```
[Try it online!](https://tio.run/##LY7BasMwEETv/Yo97tqKGmMCJUEO7cHQQ74gJKBKspNgr4RiF0rc/rrr2j3NMDxm5qY/9d3Ea@hW7K0bSzUii0q0pAqsVVBFSNpne179zLqvMSScVkjCJoppO6eEaxZWZUxj7BkUIIEqoMScxb9/u9bv3OFBdxdZNd7HxUbN1rcTkkBOJOCFafdkPN9942SnPxqHeJRSvsaovzBzGzrJVgdcSqcxJJLR2d5MoBHAc47myKe/G7MOA6wJUsgEmGni8U1Eu/EX "JavaScript (Node.js) ‚Äì Try It Online")
Signature: `(n: BigInt, f: () => BigInt, m: BigInt) => BigInt`
Input / Output `BigInt` values.
---
And it would be 47 bytes if we can assume infinite precision of floating point numbers:
```
n=>f=>g=(m,p=0)=>p*m^-~p*m?g(m/n,p*n+f()):p*m|0
```
[Try it online!](https://tio.run/##LY3BboMwEETv/Yo97oLjUtEDamSiXLjlCxCVXGPSRHhtOaRSFNJfpy7tZWc0M9p31l/6YuIpTBv2vV0atbCqB1UfFToRVEGqDpl733ynuzuie2YRMs4HJHpL0Vws8cqgAAlUDQ2WhH/2oKdPOYzeR1xt1Nx7l7oMSiKsaPtkPF/8aOWkP0aL2Eop9zHqG1b2lTrpdPj/lRCJJ6PtryYNjQBeczQtd7/wVecZCoIcXgQYEnB/ENF2@QE "JavaScript (Node.js) ‚Äì Try It Online")
[Answer]
# JavaScript, ~~55~~ 53 bytes
Takes arguments by currying, i.e. `f(r)(m)`, where `r` is the black-box randomisation function. The first 3 bytes could be removed by stipulating that [the function be pre-assigned to `r`](https://codegolf.meta.stackexchange.com/a/13707/58974).
```
r=>g=(m,y=x=m)=>y?g(m,--y,r()||(--x,z=y)):m+~x?g(m):z
```
[Try it online!](https://tio.run/##dU/BasJAFLznKzy08F7NbkMhIMpLodSChxowsRcjzTaJNqnZlXUpiSb@ehpLD146pxlmGGYK8S0Oic73hkmVZp0k1yppZGl6J@9VmE@uhUxVCXgnG8faUKfJ2xKUdk0VlUhe/bjtFWO1rQGbBhir7CPViONyeK4uJo6PXaLkQe0yvlNbiMNpEA4Wy3kwHtycNqCxz7T2PzySkXyeBeFi9rQMZ/48kv7bdDFwv34bIsmuEKO1URoUnVo7J9dxnEnO2ATVqqC/vjWxcy/X1vUi/6PIEsMzaXSeHUAhL8UeYFXZ9bq/WA3jy1Ko710HuVEveZWl8IB8L9LACG3AxfY2Rl6oXMaRjLH7AQ) (change the values of `n` & `m` in the header)
[Answer]
# [Vyxal](https://github.com/Vyxal/Vyxal), 29 bytes
```
{|n√∑¬£$‚Ä¢‚åà(¬•‚Ä†‚Öõ)¬ænhŒ≤:n·π™t>nh(¬º_)}
```
[Try it Online!](https://lyxal.pythonanywhere.com?flags=&code=%7B%7Cn%C3%B7%C2%A3%24%E2%80%A2%E2%8C%88%28%C2%A5%E2%80%A0%E2%85%9B%29%C2%BEnh%CE%B2%3An%E1%B9%AAt%3Enh%28%C2%BC_%29%7D&inputs=&header=%CE%BB1%7C&footer=%3B%E2%86%92f%20%E2%9F%A85%7C12%7C%CE%BB0%7C5%CA%81%E2%84%85%3B%E2%9F%A9%20%E2%86%90f%20%0A)
This is a whole bunch of yucky stuff that is lowkey disturbing. I really need to make functions nicer to deal with in the rewrite.
A lambda submission, that takes a single argument, `[n, m, f]`.
## Explained
```
{|n√∑¬£$‚Ä¢‚åà(¬•‚Ä†‚Öõ)¬ænhŒ≤:n·π™t>nh(¬º_)}
{|                             # while the top of the lambda stack is truthy:
  n√∑                           #   push all the contents of the input onto the stack
    ¬£                          #   and place "f" into the register.
     $‚Ä¢‚åà                       #   push ceil(log_n(m))
        (¬•‚Ä†‚Öõ)                  #   and that many times, push the result of f() onto the global array
             ¬æ                 #   push the global array, containing ceil(log_n(m)) numbers
              nhŒ≤              #   and convert from base n
                 :n·π™t>         #   push ^ > m
                      nh(¬º_)   #   and clear the global array
                            }  # close the while loop (we need this because lambda submission)
```
[Answer]
# [JavaScript (Node.js)](https://nodejs.org), 50 bytes
```
(r,n,m)=>g=(i=1,j=0)=>i<m?g(i*n,j*n+r()):j<m?j:g()
```
[Try it online!](https://tio.run/##fY/BSsNAFEX3@YosFN5rJ2MUAtI6FcQKXdhCk7ppihmTNM7YvCnTQVpq/PUYRbAr7@7cxeFeLd/lLrdq6wIyRdmSiLxaXHtWPIvRo3Sv3EoqTA3Yo4/QW4sWLCNWoxhVApS4ZFqEHaib@rYC1SOme9S3gDjQXaUHFWCbG9qZTck3poIsGceJP19M44F/dlz/2gAb9i@mlNL9JE7mk7tFMplNU5o9jed@9PajSik4SYbe2lgw4tgwJaIwDIcqCIZollr8KVci@OyalXe6bvaiy9zxkpxV5Q4M8lpuAZZ7dlh1L/f97Hs1HC6iELkzD2pfFnCFfCuL2EnrIMLmPEOujaIspQzbLw "JavaScript (Node.js) ‚Äì Try It Online")
generate ceil(logn(m)) random numbers, convert these from base n to an integer, and reject-and-try-again if the result's greater than or equal to m.
# [JavaScript (Node.js)](https://nodejs.org), 49 bytes
```
r=>g=(m,y=x=m)=>y?g(m,--y,r()?z=y:--x):1-x?g(m):z
```
[Try it online!](https://tio.run/##dU9LS8NAGLznV@SgsJ9m11gISMqXglghB1toUi9NMWteJja7YbNI0od/PabioRfnNMMMw0zFv3ibqLLRVMg0GwROjBofDIVv6L1w/cEUF6msCdyIo23kOCj0CiS11WOHNaDXz4pRUdpbisBsj71LaQfuPe3OBrj7IZGilbuM7WRB4nAehOZqvQhc8@qQEwVj5mT9wyMRiSc/CFf@4zr0l4tILF/nK9P5/G2IBL1ADEYuFZF4OFklOrZtT0tKpyA3Ff71bZF@j3JrXC5avldZolkmtCqzlkhgNW8I2XRWvx3vdbfxeSnp7xwbmJbPZZelZAKs4WmgudLEgdN1DKySpYgjEcPwAw "JavaScript (Node.js) ‚Äì Try It Online")
From Shaggy's
[Answer]
# [C (gcc)](https://gcc.gnu.org/), 59 bytes
```
r;c;g(n,m,f)int(*f)();{for(r=0,c=m;c--;r%=m)r=r*n+f();r=r;}
```
[Try it online!](https://tio.run/##hZPxbqMwDMb/Xp7C2omRQJCg02naMp5kmyYWoI3UhCrQm3QTr37MTstaetodEoLYn@1fPoLO1lpPk1darbmTVrbCuIEnreBCfbSd577MpS6t0lmmfFRa4UufuLTFPL6pcUI9OMXo4V3NBXyAb4a9d@ArWkdOwch@dabG@K6phtedpxl6U3nQGwlUqbu9G7CUvW/MtuFhmWUCdvuBdCgWis2L@NnFuDw2Dd1e3zAeSC76hWzLr6NV/QDRbQ0lXEtSHRSKLZjiH7GcE4v2G9MP3dmABOpqqGgAxYxiaBVwU@bKPDqVpkacc0kSP5mX0JUKbGUcOcUArz74NBjb8FyghGJBdHgNjgDvdeVoHzVENe7gBjlurICyhNXc6FiYgKN5uFNdbbedxu/am99N1xL/POBLa5da@70WhsbuTpHZWVciEx6Hh2dHzp7VHDwhf7B/rvDxCD/zBM9DMOgETRc1R1k4QmqRCbt5ovxLmp5SI7s6/zZOBp34G3DNo1oC3e0MKcH@n9P@i/PwtyDtBaz9DnZBdWS20l4wL09jFsviPj@mRzZOd1DcsqKA4o6toLj/o9ttte6n7P0T "C (gcc) ‚Äì Try It Online")
[Answer]
# [JavaScript](https://www.javascript.com/), 36 bytes
```
(n,m,f)=>(g=p=>p&&g(p-1)*n+f())(m)%m
```
[Try it online!](https://tio.run/##dVJNb@IwEL3zK0bqB3YTIlJUdUsapJUqbj31iFBrQRy8iu3IuFmqNL@djk1Cw3bhgCfz5s28@fjDKrZdGVHaUfVr/5Tu0lm90mqriywqdE52NDGZfTcKdkmTDObpnqhQhpymM5KnZTorr69zUo5ieqMCTiglkl7JfZFZWDPLIIVFrab3oZzGkyZEM46dfe/tW2c@NMtkMODvamWFVsAKkavXrTVC5QSfsMgUhXoA@HNZTSYxKTphBAhHaOV2k3hccCAOn8GYOhADhzCMTFZmzDqEQuD8h@i2L//d9BSUWNq@bsTWasKM6YpzbYA4BQIEyvwGOmUVlkP3QiyTo78/ytPWRGT1y8Gk4a0TNpyi2uA0qupHTXyUbwrfi2NjFQV6KNn4RjqhNW6qAc39JvozVO1qVPYXfhvDPohqEzhU/kBli3pexEVRkHHrkj9dLgdHPnE38szsJjJMrbUkeCKfXVBvmimME3weQd3coRUEgn4P1pdc4GEtg6Dr8Rxf/ofv9S3m7dH@k@RkO28KM13WqgGsNn3rRtq/Bi@m9Z9y58QxQ@RL/Odn@PIMfzg67jJ@GFOMaPZf "JavaScript (V8) ‚Äì Try It Online")
This answer works in all JS versions after 2015
**Edit #1:** -3 bytes thanks to [Shaggy](https://codegolf.stackexchange.com/users/58974/shaggy)
]