Improved the ARABIC function to handle short-form roman numerals

This commit is contained in:
Paul Kievits 2020-03-06 10:34:51 +01:00 committed by Adrien Crivelli
parent 560e672b30
commit a08415a7b5
3 changed files with 73 additions and 21 deletions

View File

@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com) The format is based on [Keep a Changelog](https://keepachangelog.com)
and this project adheres to [Semantic Versioning](https://semver.org). and this project adheres to [Semantic Versioning](https://semver.org).
## [Unreleased]
- Improved the ARABIC function to also hande short-hand roman numerals
## [1.11.0] - 2020-03-02 ## [1.11.0] - 2020-03-02
### Added ### Added

View File

@ -61,34 +61,17 @@ class MathTrig
} }
// Convert the roman numeral to an arabic number // Convert the roman numeral to an arabic number
$lookup = [
'M' => 1000, 'CM' => 900,
'D' => 500, 'CD' => 400,
'C' => 100, 'XC' => 90,
'L' => 50, 'XL' => 40,
'X' => 10, 'IX' => 9,
'V' => 5, 'IV' => 4, 'I' => 1,
];
$negativeNumber = $roman[0] === '-'; $negativeNumber = $roman[0] === '-';
if ($negativeNumber) { if ($negativeNumber) {
$roman = substr($roman, 1); $roman = substr($roman, 1);
} }
$arabic = 0; try {
for ($i = 0; $i < strlen($roman); ++$i) { $arabic = self::calculateArabic(str_split($roman));
if (!isset($lookup[$roman[$i]])) { } catch (\Exception $e) {
return Functions::VALUE(); // Invalid character detected return Functions::VALUE(); // Invalid character detected
} }
if ($i < (strlen($roman) - 1) && isset($lookup[substr($roman, $i, 2)])) {
$arabic += $lookup[substr($roman, $i, 2)]; // Detected a match on the next 2 characters
++$i;
} else {
$arabic += $lookup[$roman[$i]]; // Detected a match on one character only
}
}
if ($negativeNumber) { if ($negativeNumber) {
$arabic *= -1; // The number should be negative $arabic *= -1; // The number should be negative
} }
@ -96,6 +79,47 @@ class MathTrig
return $arabic; return $arabic;
} }
/**
* Recursively calculate the arabic value of a roman numeral.
*
* @param array $roman
* @param int $sum
* @param int $subtract
*
* @return int
*/
protected static function calculateArabic(array $roman, &$sum = 0, $subtract = 0)
{
$lookup = [
'M' => 1000,
'D' => 500,
'C' => 100,
'L' => 50,
'X' => 10,
'V' => 5,
'I' => 1,
];
$numeral = array_shift($roman);
if (!isset($lookup[$numeral])) {
throw new \Exception('Invalid character detected');
}
$arabic = $lookup[$numeral];
if (count($roman) > 0 && isset($lookup[$roman[0]]) && $arabic < $lookup[$roman[0]]) {
$subtract += $arabic;
} else {
$sum += ($arabic - $subtract);
$subtract = 0;
}
if (count($roman) > 0) {
self::calculateArabic($roman, $sum, $subtract);
}
return $sum;
}
/** /**
* ATAN2. * ATAN2.
* *

View File

@ -33,4 +33,28 @@ return [
-2018, -2018,
'-MMXVIII', '-MMXVIII',
], ],
[
499,
'CDXCIX'
],
[
499,
'LDVLIV'
],
[
499,
'XDIX'
],
[
499,
'VDIV'
],
[
499,
'ID'
],
[
'#VALUE!',
'WRONG'
],
]; ];