




P

1




{\displaystyle P_{1}}







P

0




{\displaystyle P_{0}}







P

1




{\displaystyle P_{1}}







P

0




{\displaystyle P_{0}}







P

0




{\displaystyle P_{0}}







P

1




{\displaystyle P_{1}}




Task details

 Use your language's random number generator to create a function/method/subroutine/... randN that returns a one or a zero, but with one occurring, on average, 1 out of N times, where N is an integer from the range 3 to 6 inclusive.
 Create a function unbiased that uses only randN as its source of randomness to become an unbiased generator of random ones and zeroes.
 For N over its range, generate and show counts of the outputs of randN and unbiased(randN).


The actual unbiasing should be done by generating two numbers at a time from randN and only returning a 1 or 0 if they are different. As long as you always return the first number or always return the second number, the probabilities discussed above should take over the biased probability of randN.

This task is an implementation of Von Neumann debiasing, first described in a 1951 paper.




program Bias_Unbias
  implicit none
 
  integer, parameter :: samples = 1000000
  integer :: i, j
  integer :: c1, c2, rand
 
  do i = 3, 6
    c1 = 0
    c2 = 0
    do j = 1, samples
      rand = bias(i)
      if (rand == 1) c1 = c1 + 1
      rand = unbias(i)
      if (rand == 1) c2 = c2 + 1
    end do
    write(*, "(i2,a,f8.3,a,f8.3,a)") i, ":", real(c1) * 100.0 / real(samples), &
                                     "%", real(c2) * 100.0 / real(samples), "%"
  end do
 
contains
 
function bias(n)
  integer :: bias
  integer, intent(in) :: n
  real :: r
 
  call random_number(r)
  if (r > 1 / real(n)) then
    bias = 0
  else
    bias = 1
  end if
end function
 
function unbias(n)
  integer :: unbias
  integer, intent(in) :: n
  integer :: a, b
 
  do
    a = bias(n)
    b = bias(n)
    if (a /= b) exit
  end do
  unbias = a     
end function
 
end program