Soloway's recurring rainfall
Soloway's Recurring Rainfall is commonly used to asses general programming knowledge by requiring basic program structure, input/output, and program exit procedure.
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
The problem:
Write a program that will read in integers and output their average. Stop reading when the value 99999 is input.
References:
- http://cs.brown.edu/~kfisler/Pubs/icer14-rainfall/icer14.pdf
- https://www.curriculumonline.ie/getmedia/8bb01bff-509e-48ed-991e-3ab5dad74a78/Seppletal-2015-DoweknowhowdifficulttheRainfallProblemis.pdf
- https://en.wikipedia.org/wiki/Moving_average#Cumulative_average
Ada
with Ada.Text_IO;
with Ada.Text_IO.Unbounded_IO;
with Ada.Strings.Unbounded;
with Ada.Integer_Text_IO;
with Ada.IO_Exceptions;
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;
Clear_String : Ada.Strings.Unbounded.Unbounded_String;
begin
Ada.Text_IO.Put("Enter rainfall int, 99999 to quit: ");
Ada.Integer_Text_IO.Get(Input_Integer);
return Input_Integer;
exception
when Ada.IO_Exceptions.Data_Error =>
Ada.Text_IO.Put_Line("Invalid input");
-- 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);
Clear_String := Ada.Text_IO.Unbounded_IO.Get_Line;
-- 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;
Ada.Text_IO.Put("New Average: ");
Ada.Text_IO.Put_Line(Float'image(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;
WHILE
INT n := 0;
WHILE
STRING s;
print( ( "Enter rainfall (integer) or ", whole( end value, 0 ), " to quit: " ) );
read( ( s, newline ) );
BOOL valid := UPB s >= LWB s; # invalid if the string is empty #
FOR s pos FROM LWB s TO UPB s WHILE valid DO
IF s[ s pos ] < "0" OR s[ s pos ] > "9"
THEN
valid := FALSE # invalid characters #
ELSE
n *:= 10 +:= ( ABS s[ s pos ] - ABS "0" )
FI
OD;
NOT valid
DO
print( ( "Invalid input, please enter an integer", newline ) )
OD;
n /= end value
DO
sum +:= n;
count +:= 1;
print( ( "New average: ", fixed( sum / count, -12, 4 ), newline ) )
OD
END
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
{
static int ReadNextInput()
{
System.Console.Write("Enter rainfall int, 99999 to quit: ");
string input = System.Console.ReadLine();
if (System.Int32.TryParse(input, out int num))
{
return num;
}
else
{
System.Console.WriteLine("Invalid input");
return ReadNextInput();
}
}
static void Main()
{
double currentAverage = 0;
int currentEntryNumber = 0;
for (int lastInput = ReadNextInput(); lastInput != 99999; lastInput = ReadNextInput())
{
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 {
readf("%d", entry);
readln();
}
catch (Exception e) {
writeln("Invalid input");
readln();
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);
}
}
}
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: "
read (*,*,IOSTAT=Reason) Input
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
Java
class recurringrainfall
{
private static int GetNextInt()
{
while (true)
{
System.out.print("Enter rainfall int, 99999 to quit: ");
String input = System.console().readLine();
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();
}
}
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)
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();
std::io::stdin().read_line(&mut input_text).expect("Failed to read from stdin");
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);
}
}
}
Wren
import "./ioutil" for Input
var n = 0
var sum = 0
while (true) {
var i = Input.integer("Enter integral rainfall (99999 to quit): ", 0)
if (i == 99999) break
n = n + 1
sum = sum + i
System.print(" The current average rainfall is %(sum/n)")
}