Soloway's recurring rainfall

Soloway's recurring rainfall
You are encouraged to solve this task according to the task description, using any language you may know.

Soloway's Recurring Rainfall is commonly used to assess general programming knowledge by requiring basic program structure, input/output, and program exit procedure.

The problem:

Write a program that will read in integers and output their average. Stop reading when the value 99999 is input.

For languages that aren't traditionally interactive, the program can read in values as makes sense and stopping once 99999 is encountered. The classic rainfall problem comes from identifying success of Computer Science programs with their students, so the original problem statement is written above -- though it may not strictly apply to a given language in the modern era.

Implementation Details:

• Only Integers are to be accepted as input
• Output should be floating point
• Rainfall can be negative (https://www.geographyrealm.com/what-is-negative-rainfall/)
• For languages where the user is inputting data, the number of data inputs can be "infinite"
• A complete implementation should handle error cases reasonably (asking the user for more input, skipping the bad value when encountered, etc)

The purpose of this problem, as originally proposed in the 1980's through its continued use today, is to just show fundamentals of CS: iteration, branching, program structure, termination, management of data types, input/output (where applicable), etc with things like input validation or management of numerical limits being more "advanced". It isn't meant to literally be a rainfall calculator so implementations should strive to implement the solution clearly and simply.

References:

```with Ada.Text_IO;

procedure RecurringRainfall is
Current_Average : Float := 0.0;
Current_Count : Integer := 0;
Input_Integer : Integer;

-- Recursively attempt to get a new integer
function Get_Next_Input return Integer is
Input_Integer : Integer;
begin
Ada.Text_IO.Put("Enter rainfall int, 99999 to quit: ");
return Input_Integer;
exception
-- We need to call Get_Line to make sure we flush the kb buffer
-- The pragma is to ignore the fact that we are not using the result
pragma Warnings (Off, Clear_String);
-- Recursively call self -- it'll break when valid input is hit
-- We disable the infinite recursion because we're intentionally
-- doing this.  It will "break" when the user inputs valid input
-- or kills the program
pragma Warnings (Off, "infinite recursion");
return Get_Next_Input;
pragma Warnings (On, "infinite recursion");
end Get_Next_Input;

begin
loop
Input_Integer := Get_Next_Input;
exit when Input_Integer = 99999;

Current_Count := Current_Count + 1;
Current_Average := Current_Average + (Float(1) / Float(Current_Count))*Float(Input_Integer) - (Float(1) / Float(Current_Count))*Current_Average;

end loop;
end RecurringRainfall;
```

ALGOL 68

```BEGIN # read a sequence of integers, terminated by 99999 and outpout their average #
INT end value       = 99999;
INT sum            := 0;
INT count          := 0;
BOOL invalid value := FALSE;
on value error( stand in, ( REF FILE f )BOOL: invalid value := TRUE );
WHILE
INT n := 0;
WHILE
print( ( "Enter rainfall (integer) or ", whole( end value, 0 ), " to quit: " ) );
read( ( n, newline ) );
invalid value
DO
print( ( "Invalid input, please enter an integer", newline ) );
invalid value := FALSE
OD;
n /= end value
DO
sum   +:= n;
count +:= 1;
print( ( "New average: ", fixed( sum / count, -12, 4 ), newline ) )
OD
END```

Arturo

```i: 0
sum: 0

while ø [
n: input "Enter rainfall as integer (99999 to quit): "
try? -> n: to :integer n
else [
print "Input must be an integer."
continue
]
if 99999 = n -> break
'i + 1
'sum + n
print ~« The current average rainfall is |sum // i|.
]
```
Output:
```Enter rainfall as integer (99999 to quit): 145
The current average rainfall is 145.0.
Enter rainfall as integer (99999 to quit): 43678
The current average rainfall is 21911.5.
Enter rainfall as integer (99999 to quit): 9
The current average rainfall is 14610.66666666667.
Enter rainfall as integer (99999 to quit): 155
The current average rainfall is 10996.75.
Enter rainfall as integer (99999 to quit): 99999```

BASIC

Applesoft BASIC

``` 10  LET SUM = 0
20  FOR RAINFALL = 1 TO 1E38
30      INPUT "ENTER RAINFALL (AS AN INTEGER, OR 99999 TO QUIT): ";I
40      IF I = 99999 THEN  END
50      IF I <  >  INT (I) THEN  PRINT "?REENTER, MUST BE AN INTEGER": GOTO 30
60      LET SUM = SUM + I
70      PRINT "  THE NEW AVERAGE RAINFALL IS "SUM / RAINFALL
80  NEXT RAINFALL
```

QBasic

Works with: QBasic version 1.1
Works with: QuickBasic version 4.5
Works with: FreeBASIC
```n = 0
sum = 0

DO
INPUT "Enter integral rainfall (99999 to quit): ", i
IF i = 99999 THEN
EXIT DO
ELSEIF (i < 0) OR (i <> INT(i)) THEN
PRINT "Must be an integer no less than 0, try again."
ELSE
n = n + 1
sum = sum + i
PRINT "  The current average rainfall is"; sum / n
END IF
LOOP
```
Output:
`Same as FreeBASIC entry.`

BASIC256

```n = 0
sum = 0

while True
input "Enter integral rainfall (99999 to quit): ", i
if i = 99999 then exit while
if (i < 0) or (i <> int(i)) then
print "Must be an integer no less than 0, try again."
else
n += 1
sum += i
print "  The current average rainfall is "; sum/n
end if
end while```
Output:
`Same as FreeBASIC entry.`

True BASIC

Works with: QBasic
```LET n = 0
LET sum = 0

DO
PRINT "Enter integral rainfall (99999 to quit): "
INPUT i
IF i = 99999 THEN
EXIT DO
ELSEIF (i < 0) OR (i <> INT(i)) THEN
PRINT "Must be an integer no less than 0, try again."
ELSE
LET n = n + 1
LET sum = sum + i
PRINT "  The current average rainfall is"; sum / n
END IF
LOOP
END
```
Output:
`Same as QBasic entry.`

Yabasic

```// Rosetta Code problem: https://rosettacode.org/wiki/Soloway%27s_Recurring_Rainfall
// by Jjuanhdez, 09/2022

n = 0
sum = 0

do
input "Enter integral rainfall (99999 to quit): " i
if (i < 0) or (i <> int(i)) then
print "Must be an integer no less than 0, try again."
elsif i = 99999
break
else
n = n + 1
sum = sum + i
print "  The current average rainfall is ", sum/n
end if
loop```
Output:
`Same as FreeBASIC entry.`

C

```#include <stdio.h>

int main(int argc, char **argv)
{
// Unused variables
(void)argc;
(void)argv;

float currentAverage = 0;
unsigned int currentEntryNumber = 0;

for (;;)
{
int ret, entry;

printf("Enter rainfall int, 99999 to quit: ");
ret = scanf("%d", &entry);

if (ret)
{
if (entry == 99999)
{
printf("User requested quit.\n");
break;
}
else
{
currentEntryNumber++;
currentAverage = currentAverage + (1.0f/currentEntryNumber)*entry - (1.0f/currentEntryNumber)*currentAverage;

printf("New Average: %f\n", currentAverage);
}
}
else
{
printf("Invalid input\n");
while (getchar() != '\n');	// Clear input buffer before asking again
}
}

return 0;
}
```

C++

```#include <iostream>
#include <limits>

int main()
{
float currentAverage = 0;
unsigned int currentEntryNumber = 0;

for (;;)
{
int entry;

std::cout << "Enter rainfall int, 99999 to quit: ";
std::cin >> entry;

if (!std::cin.fail())
{
if (entry == 99999)
{
std::cout << "User requested quit." << std::endl;
break;
}
else
{
currentEntryNumber++;
currentAverage = currentAverage + (1.0f/currentEntryNumber)*entry - (1.0f/currentEntryNumber)*currentAverage;

std::cout << "New Average: " << currentAverage << std::endl;
}
}
else
{
std::cout << "Invalid input" << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}

return 0;
}
```

C#

```namespace RosettaCode
{
class CSharpRecurringRainfall
{
{
System.Console.Write("Enter rainfall int, 99999 to quit: ");

if (System.Int32.TryParse(input, out int num))
{
return num;
}
else
{
System.Console.WriteLine("Invalid input");
}
}

static void Main()
{
double currentAverage = 0;
int currentEntryNumber = 0;

{
currentEntryNumber++;
currentAverage = currentAverage + (1.0/(float)currentEntryNumber)*lastInput - (1.0/(float)currentEntryNumber)*currentAverage;
System.Console.WriteLine("New Average: " + currentAverage);
}
}
}
}
```

D

```import std.stdio;

void main()
{
float currentAverage = 0;
uint currentEntryNumber = 0;

for (;;)
{
int entry;

write("Enter rainfall int, 99999 to quit: ");

try {
}
catch (Exception e) {
writeln("Invalid input");
continue;
}

if (entry == 99999) {
writeln("User requested quit.");
break;
} else {
currentEntryNumber++;
currentAverage = currentAverage + (1.0/currentEntryNumber)*entry - (1.0/currentEntryNumber)*currentAverage;

writeln("New Average: ", currentAverage);
}
}
}
```

Delphi

Works with: Delphi version 6.0

Although Delphi supports console applications that use simple keyboard input and teletype output, the primary focus of the language is GUI development. Consequently, I've produced a GUI version of the problem that uses the "TMemo" component to simulate a console interface.

To get the TMemo to behave like a console application, I've created an object that captures keyboard into to the TMemo and can return the keystrokes a chars, integers or reals. The object, which is called "TKeyWaiter," is simply created and attached to a TMemo component. While the object is alive, it will capture key stroke and return chars, integers or reals. It can be destroyed as soon as it is no longer needed. In fact, in this code, I create and destroy it for every input. The creation overhead is so low that there is no reason to create a global copy and keep it alive while the program is operating.

```{This code would normally be in a library somewhere, but it is included here for clarity}

{TKeywaiter interface}

type TKeyWaiter = class(TObject)
private
FControl: TWinControl;
FControlCAbort: boolean;
protected
procedure HandleKeyPress(Sender: TObject; var Key: Char);
public
KeyChar: Char;
ValidKey: boolean;
AbortWait: boolean;
constructor Create(Control: TWinControl);
function WaitForKey: char;
function WaitForInteger: integer;
function WaitForReal: double;
property ControlCAbort: boolean read FControlCAbort write FControlCAbort;
end;

{ TMemoWaiter implementation }

type TControlHack = class(TWinControl) end;

constructor TKeyWaiter.Create(Control: TWinControl);
{Save the control we want to wait on}
begin
FControl:=Control;
FControlCAbort:=False;
end;

procedure TKeyWaiter.HandleKeyPress(Sender: TObject; var Key: Char);
{Handle captured key press}
begin
KeyChar:=Key;
ValidKey:=True;
if ControlCAbort then AbortWait:=KeyChar = #\$03;
end;

function TKeyWaiter.WaitForKey: char;
{Capture keypress event and wait for key press control}
{Spends most of its time sleep and aborts if the user}
{sets the abort flag or the program terminates}
begin
ValidKey:=False;
AbortWait:=False;
TControlHack(FControl).OnKeyPress:=HandleKeyPress;
repeat
begin
Application.ProcessMessages;
Sleep(100);
end
until ValidKey or Application.Terminated or AbortWait;
Result:=KeyChar;
end;

function TKeyWaiter.WaitForInteger: integer;
var C: char;
var S: string;
begin
Result:=0;
S:='';
{Wait for first numeric characters}
repeat
begin
C:=WaitForKey;
if AbortWait or Application.Terminated then exit;
end
until C in ['+','-','0'..'9'];
{integer until non-integer arrives}
repeat
begin
S:=S+C;
C:=WaitForKey;
if AbortWait or Application.Terminated then exit;
end
until not (C in  ['+','-','0'..'9']);
Result:=StrToInt(S);
end;

type TCharSet = set of char;

function TKeyWaiter.WaitForReal: double;
var C: char;
var S: string;
const RealSet: TCharSet = ['-','+','.','0'..'9'];
begin
Result:=0;
S:='';
{Wait for first numeric characters}
repeat
begin
C:=WaitForKey;
if AbortWait or Application.Terminated then exit;
end
until C in RealSet;
{integer until non-integer arrives}
repeat
begin
S:=S+C;
C:=WaitForKey;
if AbortWait or Application.Terminated then exit;
end
until not (C in RealSet);
Result:=StrToFloat(S);
end;

{===========================================================}

function WaitForReal(Memo: TMemo; Prompt: string): double;
{Wait for double entered into TMemo component}
var KW: TKeyWaiter;
begin
{Use custom object to wait for and capture reals}
KW:=TKeyWaiter.Create(Memo);
try
Memo.SelStart:=Memo.SelStart-1;
Memo.SetFocus;
Result:=KW.WaitForReal;
finally KW.Free; end;
end;

var Count: integer;
var Average: double;

procedure RecurringRainfall(Memo: TMemo);
var D: double;
begin
Count:=0;
Average:=0;
while true do
begin
D:=WaitForReal(Memo,'Enter integer rainfall (99999 to quit): ');
if Application.Terminated then exit;
if (Trunc(D)<>D) or (D<0) then
begin
continue;
end;
if D=99999 then break;
Inc(Count);
Average := Average + (1 / Count) * D - (1 / Count)*Average;
end;
end;
```
Output:
```Enter integer rainfall (99999 to quit):
5.4

Must be integer >=0
Enter integer rainfall (99999 to quit):
-2

Must be integer >=0
Enter integer rainfall (99999 to quit):
5

New Average: 5.00
Enter integer rainfall (99999 to quit):
2

New Average: 3.50
Enter integer rainfall (99999 to quit):
10

New Average: 5.67
Enter integer rainfall (99999 to quit):
99999

Elapsed Time: 01:56.914 min

```

EasyLang

Translation of: BASIC256
```repeat
print "Enter integral rainfall (99999 to quit): "
i = number input
until i = 99999
if error = 1 or i < 0 or i mod 1 <> 0
print "Must be an integer no less than 0, try again."
else
n += 1
sum += i
print "  The current average rainfall is " & sum / n
.
.```

Fortran

Fortran 90

```function getNextInput() result(Input)
implicit none
integer :: Input
integer :: Reason
Reason = 1

do while (Reason > 0)
print *, "Enter rainfall int, 99999 to quit: "

if (Reason > 0) then
print *, "Invalid input"
end if
enddo

end function getNextInput

program recurringrainfall
implicit none
real        :: currentAverage
integer     :: currentCount
integer     :: lastInput
integer     :: getNextInput

currentAverage = 0
currentCount = 0

do
lastInput = getNextInput()

if (lastInput == 99999) exit

currentCount = currentCount + 1
currentAverage = currentAverage + (1/real(currentCount))*lastInput - (1/real(currentCount))*currentAverage

print *, 'New Average: ', currentAverage
enddo

end program recurringrainfall
```

FreeBASIC

```Dim As Integer n = 0, sum = 0
Dim As Single i

Do
Input "Enter integral rainfall (99999 to quit): ", i
If i = 99999 Then
Exit Do
Elseif (i < 0) Or (i <> Int(i)) Then
Print "Must be an integer no less than 0, try again."
Else
n += 1
sum += i
Print "  The current average rainfall is"; sum/n
End If
Loop

Sleep```
Output:
```Enter integral rainfall (99999 to quit): 5.4
Must be an integer no less than 0, try again.
Enter integral rainfall (99999 to quit): -2
Must be an integer no less than 0, try again.
Enter integral rainfall (99999 to quit): 5
The current average rainfall is 5
Enter integral rainfall (99999 to quit): 2
The current average rainfall is 3.5
Enter integral rainfall (99999 to quit): 10
The current average rainfall is 5.6666666666667
Enter integral rainfall (99999 to quit): 99999```

J

The specification for this task seems inadequate. So, we'll copy some features from other implementations of this task.

Specifically, we'll issue a prompt for every number requested, and reject lines which contain something that is not a number.

Implementation:

```require'general/misc/prompt'

list=. ''
while. do.
y=. (#~ >.=<.)_.".prompt'Enter rainfall int, 99999 to quit: '
if. 99999 e. y do. (+/%#)list return. end.
if. y-:y do. echo 'New average: ',":(+/%#)list=. list,y
else. echo 'invalid input, reenter'
end.
end.
}}
```

Example use:

```   task''
Enter rainfall int, 99999 to quit: 2
New average: 2
Enter rainfall int, 99999 to quit: 3
New average: 2.5
Enter rainfall int, 99999 to quit: 5
New average: 3.33333
Enter rainfall int, 99999 to quit: 7
New average: 4.25
Enter rainfall int, 99999 to quit: 11
New average: 5.6
Enter rainfall int, 99999 to quit: 99999
5.6
```

Java

```class recurringrainfall
{
private static int GetNextInt()
{
while (true)
{
System.out.print("Enter rainfall int, 99999 to quit: ");

try
{
int n = Integer.parseInt(input);
return n;
}
catch (Exception e)
{
System.out.println("Invalid input");
}
}
}

private static void recurringRainfall() {
float currentAverage = 0;
int currentEntryNumber = 0;

while (true) {
int entry = GetNextInt();

if (entry == 99999)
return;

currentEntryNumber++;
currentAverage = currentAverage + ((float)1/currentEntryNumber)*entry - ((float)1/currentEntryNumber)*currentAverage;

System.out.println("New Average: " + currentAverage);
}
}

public static void main(String args[]) {
recurringRainfall();
}
}
```

jq

The following program is mainly intended for interactive use. An appropriate invocation would be: jq -nrR -f compute-averages.jq Please note:

• a null response is regarded as an invalid entry;
• if there are no valid entries, the average is not printed;
• leading and trailing spaces in entries are ignored, and a single + or - prefix is allowed;
• an "end-of-file" condition is equivalent to the occurrence of 99999.
```def isinteger: test("^ *[+-]?[0-9]+ *\$");

def soloway:
label \$out
| foreach (inputs, null) as \$x (null;
.invalid = false
| if \$x == null then .break = true
elif (\$x|isinteger) then (\$x|tonumber) as \$n
| if \$n == 99999
then .break = true
else .sum += \$n | .n += 1
end
else .invalid = \$x
end;
if .break then ., break \$out
elif .invalid then .
else empty
end)
| (select(.invalid) | "Invalid entry (\(.invalid)). Please try again."),
(select(.break and .sum) | "Average is: \(.sum / .n)") ;

soloway```

Julia

Written for simplicity of reading rather than brevity. Changed from the originals to allow negative input, though I note that allowing negative integer input and disallowing floating point seems strange given most "real-life" negative rainfall daily numbers are less than 1 inch.

```"""
Two annotated example outputs
were given: 1) a run with three positive inputs, a zero, and
a negative number before the sentinel; 2) a run in which
the sentinel was the first and only input.
"""
function rainfall_problem(sentinel = 999999, allownegative = true)
total, entries = 0, 0
while true
print("Enter rainfall as \$(allownegative ? "" : "nonnegative ")integer (\$sentinel to exit): ")
if n == sentinel
break
elseif n == nothing || !allownegative && n < 0
else
total += n
entries += 1
println("Average rainfall is currently ", total / entries)
end
end
if entries == 0
println("No entries to calculate!")
end
end

rainfall_problem()
```

Nim

We catch exceptions related to wrong input, i.e. non integer values. Negative values are allowed. If an end of file is encountered, the program terminates with an error message.

```import std/[strformat, strutils]

const EndValue = 99999

var sum, count = 0.0

while true:

var value: int

# Read input until a valid integer if found.
var input: string
while true:
stdout.write &"Enter an integer value, {EndValue} to terminate: "
stdout.flushFile()
try:
value = input.parseInt()
break
except ValueError:
echo &"Expected an integer: got “{input}”"
except EOFError:
quit "\nEncountered end of file. Exiting.", QuitFailure

# Process value.
if value == EndValue:
echo "End of processing."
break
count += 1
sum += value.toFloat
echo &"  Current average is {sum / count}."
```
Output:

Sample session.

```Enter an integer value, 99999 to terminate: 10
Current average is 10.0.
Enter an integer value, 99999 to terminate: -20
Current average is -5.0.
Enter an integer value, 99999 to terminate: 50
Current average is 13.33333333333333.
Enter an integer value, 99999 to terminate: 3.5
Expected an integer: got “3.5”
Enter an integer value, 99999 to terminate: aaa
Expected an integer: got “aaa”
Enter an integer value, 99999 to terminate: 10
Current average is 12.5.
Enter an integer value, 99999 to terminate: 99999
End of processing.
```

Perl

FWIW

```use strict;
use warnings;

use Scalar::Util qw(looks_like_number);

my (\$periods, \$accumulation, \$rainfall);

sub so_far { printf "Average rainfall %.2f units over %d time periods.\n", (\$accumulation / \$periods) || 0, \$periods }

while () {
while () {
print 'Integer units of rainfall in this time period? (999999 to finalize and exit)>: ';
\$rainfall = <>;
last if looks_like_number(\$rainfall) and \$rainfall and \$rainfall == int \$rainfall;
print "Invalid input, try again.\n";
}
(so_far, exit) if \$rainfall == 999999;
\$periods++;
\$accumulation += \$rainfall;
so_far;
}
```
Output:
```Integer units of rainfall in this time period? (999999 to finalize and exit)>: raindrops
Invalid input, try again.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 2.00
Average rainfall 2.00 units over 1 time periods.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: hail
Invalid input, try again.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 10**0
Invalid input, try again.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 1
Average rainfall 1.50 units over 2 time periods.
Integer units of rainfall in this time period? (999999 to finalize and exit)>:
Invalid input, try again.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 999999
Average rainfall 1.50 units over 2 time periods.```

Phix

```with javascript_semantics
constant inputs = {5.4,"five",5,-2,4,10,99999}
atom n = 0, average = 0
procedure show_average()
printf(1,"  The current average rainfall is %g\n",average)
end procedure

for r in inputs do
printf(1,"Enter integral rainfall, 99999 to quit: %v\n",{r})
if not integer(r) /*or r<0*/ then
--      printf(1,"Must be a non-negative integer, try again.\n")
printf(1,"Must be an integer, try again.\n")
else
if r=99999 then exit end if
n += 1
average += (r-average)/n
show_average()
end if
end for
show_average()
```
Output:
```Enter integral rainfall, 99999 to quit: 5.4
Must be an integer, try again.
Enter integral rainfall, 99999 to quit: "five"
Must be an integer, try again.
Enter integral rainfall, 99999 to quit: 5
The current average rainfall is 5
Enter integral rainfall, 99999 to quit: -2
The current average rainfall is 1.5
Enter integral rainfall, 99999 to quit: 4
The current average rainfall is 2.33333
Enter integral rainfall, 99999 to quit: 10
The current average rainfall is 4.25
Enter integral rainfall, 99999 to quit: 99999
The current average rainfall is 4.25
```

PureBasic

```Define.i n=0, sum=0
Define.f i

If OpenConsole()
Repeat
Print("Enter integral rainfall (99999 to quit): ")
i=ValF(Input())
If i=99999
Break
ElseIf i<0 Or i<>Int(i)
PrintN("Must be an integer no less than 0, try again.")
Else
n+1
sum+i
PrintN("  The current average rainfall is "+StrF(sum/n,5))
EndIf
ForEver
EndIf```
Output:
`Same as FreeBASIC entry.`

Python

```import sys

def get_next_input():
try:
num = int(input("Enter rainfall int, 99999 to quit: "))
except:
print("Invalid input")
return get_next_input()
return num

current_average = 0.0
current_count = 0

while True:
next = get_next_input()

if next == 99999:
sys.exit()
else:
current_count += 1
current_average = current_average + (1.0/current_count)*next - (1.0/current_count)*current_average

print("New average: ", current_average)
```

Quackery

```  [ \$ "bigrat.qky" loadfile ] now!

[ 0 0
[ \$ "Enter an integer (99999 to end): "
[ input \$->n not iff
[ drop
\$ "                      Try again: " ]
again ]
dup 99999 != while
+ dip 1+
again ]
drop
cr
over 0 = iff
[ 2drop
say "No data entered." ] done
say "Average: "
swap 10 point\$ echo\$ ]                          is srr ( --> )```
Output:

As a dialogue in the Quackery shell.

```/O> srr
...
Enter an integer (99999 to end): 99999

No data entered.
Stack empty.

/O> srr
...
Enter an integer (99999 to end): not an integer
Try again: 3.14159
Try again:
Try again: 2
Enter an integer (99999 to end): -3
Enter an integer (99999 to end): 5
Enter an integer (99999 to end): -7
Enter an integer (99999 to end): 11
Enter an integer (99999 to end): -13
Enter an integer (99999 to end): 17
Enter an integer (99999 to end): 99999

Average: 1.7142857143
Stack empty.```

Raku

This task seems to be more about following (kind of vague) instructions and anticipating error conditions rather than solving a rather simple problem.

I notice that units are specified for neither measurement; time nor rainfall accumulation. Time is assumed to always increment in units of one, rainfall in some non-negative integer. "Integer" gets a little leeway in this entry. Floating point numbers or Rational numbers that are exactly equal to an Integer are allowed, even if they are technically not integers.

After update to spec:

Not going to bother to allow negative rainfall amounts. The "Negative rainfall" cited in the linked article references "total accumulated groundwater" NOT precipitation. Evaporation isn't rainfall. Much like dew or fog is not rainfall.

Further, the linked reference article for Soloway's Recurring Rainfall SPECIFICALLY discusses marking an implementation as incorrect, or at least lacking, if it doesn't ignore and discard negative entries. You can't have it both ways.

```# Write a program that will read in integers and
# output their average. Stop reading when the
# value 99999 is input.

my (\$periods, \$accumulation, \$rainfall) = 0, 0;

loop {
loop {
\$rainfall = prompt 'Integer units of rainfall in this time period? (999999 to finalize and exit)>: ';
last if \$rainfall.chars and \$rainfall.Numeric !~~ Failure and \$rainfall.narrow ~~ Int and \$rainfall ≥ 0;
say 'Invalid input, try again.';
}
last if \$rainfall == 999999;
++\$periods;
\$accumulation += \$rainfall;
say-it;
}

say-it;

sub say-it { printf "Average rainfall %.2f units over %d time periods.\n", (\$accumulation / \$periods) || 0, \$periods }
```
Output:
```# Normal operation
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 0
Average rainfall 0.00 units over 1 time periods.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 2
Average rainfall 1.00 units over 2 time periods.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 4
Average rainfall 2.00 units over 3 time periods.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 6
Average rainfall 3.00 units over 4 time periods.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 8
Average rainfall 4.00 units over 5 time periods.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 999999
Average rainfall 4.00 units over 5 time periods.

# Invalid entries and valid but not traditional "Integer" entries demonstrated
Integer units of rainfall in this time period? (999999 to finalize and exit)>: a
Invalid input, try again.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 1.1
Invalid input, try again.
Integer units of rainfall in this time period? (999999 to finalize and exit)>:
Invalid input, try again.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 2.0
Average rainfall 2.00 units over 1 time periods.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: .3e1
Average rainfall 2.50 units over 2 time periods.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 999999
Average rainfall 2.50 units over 2 time periods.

# Valid summary with no entries demonstrated.
Integer units of rainfall in this time period? (999999 to finalize and exit)>: 999999
Average rainfall 0.00 units over 0 time periods.```

RPL

Works with: HP version 28
RPL code Comment
```≪ "Enter rainfall, then ENTER" 1 DISP
"" "0123456789"
DO DO UNTIL KEY END
IF DUP2 POS THEN
ROT OVER + DUP 2 DISP ROT ROT
END
UNTIL "ENTER" == END
DROP STR→

≪ "Enter 9999 to end" 4 DISP
(0,0) 1 CF CLLCD
IF DUP 9999 == THEN 1 SF
ELSE
1 R→C +
"Average = " OVER RE LAST IM / →STR +
3 DISP
END
UNTIL 1 FS? END
SWAP DROP CLMF
IFERR RE LAST IM / THEN DROP2 END
≫ 'RFALL' STO
```
```READB ( → n )
Initialize variables
Loop
if keystroke is an accepted char
add char to output and display it

until ENTER is pressed
clean stack and convert to integer

RFALL ( → )
initialize counters and flag, clear screen
loop
get rainfall
if break value then set flag
otherwise
accumulate rainfall and increment count
display average rainfall

until flag set
clean stack, unfreeze display
put average rainfall in stack if count ≠ 0

```

Ruby

```QUIT  = 99999
num   = nil
count = 0
avg   = 0.0

loop do
begin
print "Enter rainfall int, #{QUIT} to quit: "
input = gets
num = Integer(input)
rescue ArgumentError
puts "Invalid input #{input}"
redo
end
break if num == QUIT
count += 1
inv_count = 1.0/count
avg = avg + inv_count*num - inv_count*avg
end

puts "#{count} numbers entered, averaging #{average}"
```

Rust

```fn main() {

let mut current_average:f32 = 0.0;
let mut current_entry_number:u32 = 0;

loop
{
let current_entry;

println!("Enter rainfall int, 99999 to quit: ");
let mut input_text = String::new();
let trimmed = input_text.trim();
match trimmed.parse::<u32>() {
Ok(new_entry) => current_entry = new_entry,
Err(..) => { println!("Invalid input"); continue; }
};

if current_entry == 99999
{
println!("User requested quit.");
break;
}
else
{
current_entry_number = current_entry_number + 1;
current_average = current_average + (1.0 / current_entry_number as f32)*(current_entry as f32) - (1.0 / current_entry_number as f32)*current_average;

println!("New Average: {}", current_average);
}
}
}
```

Swift

```import Foundation

var mean: Double = 0
var count: Int = 0
var prompt = "Enter integer rainfall or 99999 to exit:"
var term = " "
print(prompt, terminator: term)
while let input = readLine() {
defer {
print("count: \(count), mean: \(mean.formatted())\n\(prompt)", terminator: term)
}
guard let val = Int(input) else {
print("Integer values only")
continue
}
if val == 99999 {
(prompt, term) = ("Done","\n")
break
}
count += 1
mean += Double(val)/Double(count) - mean/Double(count)
}
```

Wren

Library: Wren-ioutil
```import "./ioutil" for Input

var n = 0
var sum = 0
while (true) {
var i = Input.integer("Enter integral rainfall (99999 to quit): ")
if (i == 99999) break
n = n + 1
sum = sum + i
System.print("  The current average rainfall is %(sum/n)")
}
```
Output:

Sample session:

```Enter integral rainfall (99999 to quit): 5.4
Must be an integer, try again.
Enter integral rainfall (99999 to quit): five
Must be an integer, try again.
Enter integral rainfall (99999 to quit): 5
The current average rainfall is 5
Enter integral rainfall (99999 to quit): -2
The current average rainfall is 1.5
Enter integral rainfall (99999 to quit): 4
The current average rainfall is 2.3333333333333
Enter integral rainfall (99999 to quit): 10
The current average rainfall is 4.25
Enter integral rainfall (99999 to quit): 99999
```

XPL0

The problem is very simple except for the vague requirements for the user interface and how to deal with unaccepted rainfall amounts.

```real Rain, Sum, Count;
[Sum:= 0.;  Count:= 0.;
loop    [loop   [Text(0, "Enter rainfall amount, or 99999 to quit: ");
Rain:= RlIn(0);
if Rain < 0. then
Text(0, "Must not be negative.^m^j")
else if Floor(Rain) # Rain then
Text(0, "Must be an integer.^m^j")
else quit;
];
if Rain = 99999. then quit;
Sum:= Sum + Rain;
Count:= Count + 1.;
Text(0, "Average rainfall is ");
RlOut(0, Sum/Count);
CrLf(0);
];
]```
Output:
```Enter rainfall amount, or 99999 to quit: 5.4
Must be an integer.
Enter rainfall amount, or 99999 to quit: five
5
Average rainfall is     5.00000
Enter rainfall amount, or 99999 to quit: -2
Must not be negative.
Enter rainfall amount, or 99999 to quit: 4
Average rainfall is     4.50000
Enter rainfall amount, or 99999 to quit:
2.00000001
Must be an integer.
Enter rainfall amount, or 99999 to quit: .3e1
Average rainfall is     4.00000
Enter rainfall amount, or 99999 to quit: 99999
```