5 KiB
Executable file
if.03.22 Procedural Programming
Roman numbers
This assignment targets on string analysis and validation, pointer handling as well as a simple recursive calculation.
Introduction
Roman numbers are used since ancient ages. They are expressed via letters which have the following values:
- I: 1
- V: 5
- X: 10
- L: 50
- C: 100
- D: 500
- M: 1000
- some more higher value signs
The numerical value is calculated by simply adding the value of each letter:
MMCLXXXVII => 1000 + 1000 + 100 + 50 + 10 + 10 + 10 + 5 + 1 + 1 = 2187
In addition, values are subtracted, if one I, X, or C is placed before the next larger value.
IV => -1 + 5 = 4
IX => -1 + 10 = 9
XL => -10 + 50 = 40
CD => -100 + 500 = 400
An extension of this rule allows subtraction of the letters above if they are placed in front of even larger values
IC => -1 + 100 = 99 instead of XCIX => -10 + 100 - 1 + 10
which simplifies the usage of the numbers.
The letters V, L, D are never used as subtractive values.
Roman number letters are written in descending order of their nominal value, except for the special case of subtraction.
MCMLXVII (1967) must not be written in different order, e.g. IIVXLMCM is not allowed
Assignment
Your task is to implement an abstract data type calls RomanNumber, which encapsulates the numerical representation of a string that expresses a valid roman number.
The following functions for the ADT RomanNumber shall be implemented:
rn_is_valid_number_str
A private function which determines whether a given string represents a valid roman number. If the string contains any other characters but the above defined ones, it DOES NOT represent a valid number!
The validity can easily be done by iterating through all characters of the string and testing if the current letter is a defined one and its numerical value is equal or less the numerical letter of the previous letter. The only exception to this rule are valid subtraction patterns (e.g. IX). If the current and next letter form a valid subtraction pattern can be tested with the already implemented private functionrn_is_valid_subtraction. If such a valid pattern was detected, the string remains valid for the current letter and the check stated above can be skipped. Nevertheless, the 'next' letter (which was used to test the subtraction pattern) still need regularly be checked.rn_get_value_for_letter:
A private function that provides the numerical value of a single letter. Note thatswitch / caseinstructions work for characters as well.rn_create:
Allocates a newRomanNumberout of a statically allocated pool of data structs for the ADT. The pool ofRomanNumberdata is allocated on the global scope with a size ofMAX_ROMAN_NUMBER_COUNTas defined inroman_number.c.
It MAY be trusted, that the pool is sufficiently large to provide instances for all unit tests without the need of returning instances to the pool.
It MAY be trusted that a valid string is provided, although not necessarily a valid roman number string. If the string does not represent a valid roman number, an invalid (non-null)RomanNumbershall be provided. The given string need therefore be checked using the private functionrn_is_valid_number_str, whether the string represents a valid roman number.
If the given string is a valid roman number, its numerical value shall be calculated upon creation and stored within the ADTs data. The roman number is converted by simply adding the values of its letters, except a subtraction pattern is detected. In this case the value of the letter has to be subtracted. Use the functionrn_is_valid_subtractionto check for subtractions.
Note that an empty string is valid and results in the value zero (0), while a null-string is invalid.rn_is_valid:
Determines whether or not the givenRomanNumberis valid. It is, if it is neither 0 nor was created from an invalid roman number.rn_get_value:
Provides the numerical value of the givenRomanNumberas stored in the ADTs data or a value less than zero, if theRomanNumberis not valid.rn_gcd:
Calculates the greatest common divisor of twoRomanNumbers and returns the result again asRomanNumber.
Important note: This function DOES NOT actually calculate the GCD but uses the functionint_gcdfor this purpose. It only 'converts' the roman number back and forth.int_gcd: Actually calculates the greatest common divisor (GCD) of two positive integer values using recursion. It MAY be trusted, that the given integers are always positive.
The GCD is defined as:gcd(x, 0) = x;gcd(x, y) = gcd(y, x % y);
where%is the modulo operator.
Note the this function is independently tested and can be implemented even if the ADT is not working.
Tasks
- Create a skeleton implmentation of the ADT to make the unit tests compilable.
- Implement all required functions to make the unit tests pass.
- A main application is not required.