A method of choosing a line randomly from a file:

 Without reading the file more than once
 When substantial parts of the file cannot be held in memory
 Without knowing how many lines are in the file
Is to:

 keep the first line of the file as a possible choice, then
 Read the second line of the file if possible and make it the possible choice if a uniform random value between zero and one is less than 1/2.
 Read the third line of the file if possible and make it the possible choice if a uniform random value between zero and one is less than 1/3.
 ...
 Read the Nth line of the file if possible and make it the possible choice if a uniform random value between zero and one is less than 1/N
 Return the computed possible choice when no further lines exist in the file.


Task

 Create a function/method/routine called one_of_n that given n, the number of actual lines in a file, follows the algorithm above to return an integer - the line number of the line chosen from the file. 
The number returned can vary, randomly, in each run.
 Use one_of_n in a simulation to find what woud be the chosen line of a 10 line file simulated 1,000,000 times.
 Print and show how many times each of the 10 lines is chosen as a rough measure of how well the algorithm works.


Note: You may choose a smaller number of repetitions if necessary, but mention this up-front.

Note: This is a specific version of a Reservoir Sampling algorithm: https://en.wikipedia.org/wiki/Reservoir_sampling

with Ada.Text_IO, Ada.Numerics.Float_Random;
 
procedure One_Of_N is
 
   Num_Of_Lines: constant Positive := 10;
 
   package Rnd renames Ada.Numerics.Float_Random;
   Gen: Rnd.Generator; -- used globally
 
   function Choose_One_Of_N(Last_Line_Number: Positive) return Natural is
      Current_Choice: Natural := 0;
   begin
      for Line_Number in 1 .. Last_Line_Number loop
        if (Rnd.Random(Gen) * Float(Line_Number) <= 1.0) then
           Current_Choice := Line_Number;
        end if;
      end loop;
      return Current_Choice;
   end Choose_One_Of_N;
 
   Results: array(1 .. Num_Of_Lines) of Natural := (others => 0);
   Index: Integer range 1 .. Num_Of_Lines;
 
begin
   Rnd.Reset(Gen);
   for I in 1 .. 1_000_000 loop    -- compute results
      Index := Choose_One_Of_N(Num_Of_Lines);
      Results(Index) := Results(Index) + 1;
   end loop;
 
   for R in Results'Range loop    -- output results
      Ada.Text_IO.Put(Integer'Image(Results(R)));
   end loop;
end One_Of_N;