Jump to content

roman numerals to decimal conversion question


jodunno
 Share

Recommended Posts

so i take that to mean a fee of my choosing? How about a pint 😁

just kidding. Although, as legal notice, posting the code in public is not a consent to usage of said code. Afterall, you are the copyright holder. I can post a copyright photo here but it does not grant legal rights to use it. Too many people use other peoples work illegally. I am not one of those people.

I can analyze your logic and work it into mine but certainly not in part or in whole.

I forgot to say Thank you for all of your time and hard work. In fact, Thank you to everyone posting in this thread. I appreciate you and this community.

Best wishes,

John

Link to comment
Share on other sites

I was thinking about this whole problem and all of my coding attempts. I wondered how my code would handle repetition, so i tied it and my code failed to detect it. So i tried it using your script and your script also accepts it but oddly calculates the amount.

I tried VIIIVIII. Your script outputs 10. I would think it should be 16 but technically an invalid number. This is so complicated.

Link to comment
Share on other sites

1 hour ago, jodunno said:

I tried VIIIVIII. Your script outputs 10

The normal order is high to low and a number to that precedes a higher value is subtracted.

The first "III" are therefore subtracted from the following V, giving 5 + 2 +  1 + 1 + 1 = 10

Link to comment
Share on other sites

yes i see how it reaches ten but viiiviii is getting too far away from my goal. I suppose that i am trying to create a copyright year converter and not an addition and subtraction calculator. Which is why i say that viiiviii is not valid. Remember that my site is biology/nature related. I've added biographical notices (place of birth/death, profession etc.) I list books as references. Alot of books are very old (1400s, 1500s, 1600s, 1700s and 1800s). Alot of copyright dates are roman numerals and they do not contain non standard forms, such as vvvv for 20. My goal was emulate online calculators with a common subtractive exception.

I added a loop to my code that checks the numbers in a reversed array, thus allowing me to query if current number is less than next number then invalid. VIIIVIII gets blocked in this code. I can further retsrain repetition by only permitting certain numbers to be repeated and only 3 times. Example, CCC and III but CCCC and IIII will be blocked. I'm getting a better grip now the picture is getting clearer.

Link to comment
Share on other sites

Hi Barand,

I am not making a calculator. I will try to better explain my project. I am simply trying to create my own date converter (roman numerals to arabic/decimal numbers) allowing common date subtractive numerals but restricting subtractives to five. Again, I forgot how roman numerals work except for basic numers. I had to look up D (500) for example. I often have to calculate the dates in books for my literary references of biographical notices. An example citation for Ulisse Aldrovandi (Ulysses Aldrovandi):

Bonucci, Anicio . Plauso Letterario per la Restaurazione della Sala Urbana ed Inaugurazione dell'aula Piana nel Palazzo Apostolico di Bologna . Artikel: Elogio di Ulisse Aldrovandi . Seiten 68-73 . Bologna (Italien) 1852 (M DCCC LII)

I often have to mentally convert the dates because they are only published in Roman numerals. I started using online converters to spare me from having to calculate. But none of the online converters that i found allow subtractive numbers. I found an old book from 1595 and the published date was in Roman Numerals as MDVC. I couldn't find an online converter that accepts this format. Again, i've seen subtractive numbers in books but they seem to stop at 5. I've not seen viic, so it appears to me that old scholars accepted subtractive dates with a limit of five. I want to permit these subtractions but stick to conventional numerals for all other dates. Thus viiiviii is not conventional and i'd like to ignore it. 

I further tweaked my code and it is now blocking the following numerals: xicx, ixcx, iiilxv, viiiviii. So my code seems like it is working now. My code accepts MDVC but not MDVIIC. I am happy. It is actually working.

Meantime, i hope that i can list links here. I am certainly not spamming, endorsing or advertising. If the following links are deemed inappropriate then have a mod delete them and i am sorry. So these are the sites that i was using for quick date conversions (none of the sites accept mdvc, which is annoying):

www.romannumerals.org/converter
www.calculatorsoup.com/calculators/conversions/roman-numeral-converter.php
www.rapidtables.com/convert/number/roman-numerals-converter.html

I thought that it will be nice to make my own converter for my website but tweak it to accept common subtractive numerals in dates. Like mdvc.

By the way, i cant visit the rapidtables site anymore unless i use kmeleon browser. LOL. i got mad at youtube for the ad bombardments that i get lately. I decided to remove my adblocker ublock origin and go for the kill. I installed tinywall open source browser, installed fiddler, and editied the fiddler HOSTS list since Microsoft erases any changes that i make to my system HOSTS file. I am also sick of MS updates interrupting me. I blocked Windows Updates, Mozilla communications, telemetry and ad sites/uris. I blocked youtube ads and popups. Which reminds me, i also enabled custom css in Firefox to remove annoying css cookie overlays since websites are trying to detect ublock and nag me about it. I went back to private filtering (fiddler, custom css and firewall). Now cloudflare tries to deem my system as a security threat. I should sue them because they are the threat. I don't have to set up my system for ads, tracking and espionage or be labelled a security threat. I'm mad. These tech companies go too far. Anyway, now my stsem is tight and rapidtables is not functioning (fiddler shows why). Thus lately, i've been using calculatorsoup instead. While waiting for my own converter to be fully operational.
 

Link to comment
Share on other sites

Hi Barand,

I got my program to do all of the tings that i want it to do. I just have to finish the code by producing a decimal/arabic number and verify that all of the numbers are correct.

I have learned something about Roman numerals today that i find interesting. I do not rmember hearing about this problem before. I have given this problem a name: "The Nine Hole". Your code also falls into the "Nine Hole". What am i talking about? how do you know that ixx is 19 and not 1? ixx is 10-9 or 20-1, depending on how you see it. My code jumps over the Nine Hole with a code block on the ix as an invalid subtraction followed by ten. Your code calculates 19. I never thought about this problem before. I didn't realize that such a problem exists. Do you see it? ix, iix, iiix, ivx, vx, vix, viix, viiix, ixx (also 20-1). I have decided to keep my "jumping over the Nine Hole code", which i will also explain on my website.

Meantime, i am satisfied with my code for now. I will try to wrap it up later or tomorrow. Then i will test it with numbers 1-3999. Then i will test it with odd and irregular numerals. If everything works as expected , then i am finished wih this nightmare of a project. And i will have a converter which accepts subtractive numbers up to five.

Best wishes,

John

Link to comment
Share on other sites

ixx really shouldn't be calculated and my code skips it. I prefer it be skipped. Furthermore, i notice other numerals that should be ignored according to research and comparison with printed material: vv,vvv,vvvv, ll,lll,llll, dd,ddd,dddd. 2021 really should not be processed as dddixxii. I also noticed that old books use the letter j for a final i in a series of this numeral: ij, iij, vij, viij. I've added this snippet of code to my program to permit the usage of the letter j:

$RomanNumeralInput = str_replace('J', 'I', $RomanNumeralInput);

I added the following code at the end of my script (after Isolation so that subtractive numbers are not factored) to block repeated characters above four times (three is the standard but i've seen iiii and cccc in published material):

//3. check for numerals repeated greater than four times and exclude L,D
foreach (count_chars($RomanNumeralInput, 1) as $i => $val( {
  if ($val > 4) { $invalid = 1; $invalidRule = 30; break; }
  if ($val > 1 && $val <= 4 && chr($i) === 'L' || chr($i) === 'D') { $invalid = 1; $invalidRule = 31; break; }
}
// show error message and rule violation which helps during development process.
if ($invalid) { echo $RomanNumeralInput . ' is a nonstandard Roman Numeral. (Rule number: ') . $invalidRule . ')'; exit; }

I really just wanted a date converter that accepts subtractions up to V (MDVC) and permits repeated numerals up to four times (IIII, CCCC). I also wanted to block irregular and nonstandard numerals. One can argue that VC is non standard but it is published in old books. Thus, i aim to create a converter that will help users convert the numerals that they may see in old books. I am getting closer to completing my code. Adding J is also something that i want to support. I am going to add the conversion soon, then see how it handles conversions from 1-to-3999 along with subtractions.

Your code is clean and efficient for sure. I need to learn how to be a better coder. I am just adamant about sticking to my design. I don't want to process ixx, viiiviii, vvvv, ixi, etc.

Best wishes,

John

Link to comment
Share on other sites

Hi gw1500se,

i don't know how to define the scholarly subtraction but it certainly isn't invalid. Some mathematicians (which noone has ever heard of) suddenly hold themselves higher than, say Carl von Linne, and deem MDVC as an invalid numeral. However, some of the world's smartest people have published books with these 'invalid' numerals. I want to convert these numerals that you may see in old books and not show a message that it is invalid. I have only seen numbers I-5 used in irregular subtraction dates: mdvc, mdic etc. I've not seen MDVIIC or MDVIXC. I want to limit irregular subtractions to five while ignoring any other subtractions until later in the code. I like the limit and i want the limit. I have the limit.

Filter number 2 handles these lower numbers used in irregular subtractions:

//2. subtraction less than 5 should be valid in this converter
$validSubtraction = array('IV', 'III', 'II', 'I', 'V');
foreach ($validSubtraction as $m) {
  foreach ($FollowedBy as $n) {
    $pos = stripos($RomanNumeralInput, $m . $n);
    if ($pos !== false) { // 
      if ($m === $n) { $invalid = 1; $invalidRule = 20; break(2); }
      if ($pos > 0 && $RomanNumeralInput[$pos-1] === 'I') { $invalid = 1; $invalidRule = 21; break(2); }
      if ($pos > 0 && $RomanDecimal[$RomanNumeralInput[$pos-1]] < $RomanDecimal[$n]) { $invalid = 1; $invalidRule = 22; break(2); }
      $subtraction = 1; $subtractionCount = strlen($m . $n); $subtractionIsolated = $m . $n; $calculateSubtraction = $RomanDecimal[$n] - $RomanDecimal[$m];
      if ($pos + $subtractionCount < strlen($RomanNumeralInput)) {
        if ($calculateSubtraction > $RomanDecimal[$RomanNumeralInput[$pos + $subtractionCount]]) { $invalid = 1; $invalidRule = 23; break(2); }
      }
      $RomanNumeralInput = str_replace($m.$n, '', $RomanNumeralInput);
      break(2); }
  }
}
if ($invalid) { echo ' is a nonstandard Roman Numeral (Rule number: ' . $invalidRule . ')'; exit; }

This code works. Later, i handle all other subtractions like everyone else. loop through the array holding the submitted numeral. Then simply use an if statement. If current numeral less than next numeral, then subtractive.

I have tried my code on numbers 1-100, 200, 300, 400, 500, 1000, 3999, MDVC etc. I have no problems yet. MDCM is handled normally in my code. I will finish the code tomorrow, then loop through 1-3999 and see how it goes. Then i will try various irregular combinations and see how the code holds up. I'll post reults. Maybe someone can help clean up and tighten my code.

Best wishes,

John

Link to comment
Share on other sites

Attached is a gift for you so you can test all numbers from 1 - 3999

Sample contents...

I
II
III
IV
V
VI
VII
VIII
IX
X
XI
XII
XIII
XIV
XV
XVI
XVII
XVIII
XIX
XX
.
.
MCMVC
MCMXCVI
MCMXCVII
MCMXCVIII
MCMIC
MM
MMI
MMII
MMIII
MMIV
MMV
.
.
MMMCMXC
MMMCMXCI
MMMCMXCII
MMMCMXCIII
MMMCMXCIV
MMMCMVC
MMMCMXCVI
MMMCMXCVII
MMMCMXCVIII
MMMCMIC

 

roman_test.txt

Link to comment
Share on other sites

Hi Barand, Thank you for the lovely gift 🙂 I will finish testing today. I have a physical therapy session in the afternoon. Hopefully, i can put it all together after my appointment. I think that the program is working as expected but time will tell.

Best wishes,

John

Link to comment
Share on other sites

Hi Barand,

I created a script for decimal to roman last week. I am certain that my approach is different than yours but i get the job done. I added a loop so that my code prints numerals 1-3999. Decimal to Roman is easy if we only convert to standard Roman numerals. Converting from unknown possibly nonstandard possibly invalid roman numerals to decimal is a bit more difficult. I suppose that one could make a 3999 roman numeral valued array and call it a day but i like to try to solve the problems programmatically. If failure happens and i can't find a way to filter correctly then the 3999 value array is my only hope.

Here is my Decimal to Roman converter using basic arithmetic of places. Everyone, take your places! 😃

<?php
//John's PHP Decimal number to Roman Numeral converter v1
$Ones = array('I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX');
$Tens = array('X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC');
$Hundreds = array('C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM');
$Thousands = array('M', 'MM', 'MMM');

for ($j = 1; $j < 4000; $j++) {
  $PlaceCount = strval(strlen($j));
  $Places = str_split($j);
  $RomanNumeral = null;
  switch ($PlaceCount) {
    case '1': $RomanNumeral = $Ones[$j - 1]; break;
    case '2': $RomanNumeral .= $Tens[$Places[0] - 1]; if (!empty($Places[1])) { $RomanNumeral .= $Ones[$Places[1] - 1]; } break;
    case '3': $RomanNumeral .= $Hundreds[$Places[0] - 1];
        if (!empty($Places[1])) { $RomanNumeral .= $Tens[$Places[1] - 1]; }
        if (!empty($Places[2])) { $RomanNumeral .= $Ones[$Places[2] - 1]; } break;
    case '4': $RomanNumeral .= $Thousands[$Places[0] - 1];
        if (!empty($Places[1])) { $RomanNumeral .= $Hundreds[$Places[1] - 1]; }
        if (!empty($Places[2])) { $RomanNumeral .= $Tens[$Places[2] - 1]; }
        if (!empty($Places[3])) { $RomanNumeral .= $Ones[$Places[3] - 1]; } break;
  }
  echo $RomanNumeral . '<br>';
}

?>

 

Link to comment
Share on other sites

A similar approach to mine

function ad_litera ($n) {
    if ($n >3999) return 'NaN';
    
    $n2r = [  1000 => [ 1 => 'M', 2 => 'MM', 3 => 'MMM' ],
              100  => [ 1 => 'C', 2 => 'CC', 3 => 'CCC', 4 => 'CD', 5 => 'D', 6 => 'DC', 7 => 'DCC', 8 => 'DCCC', 9 => 'CM' ],
              10   => [ 1 => 'X', 2 => 'XX', 3 => 'XXX', 4 => 'XL', 5 => 'L', 6 => 'LX', 7 => 'LXX', 8 => 'LXXX', 9 => 'XC' ],
              1    => [ 1 => 'I', 2 => 'II', 3 => 'III', 4 => 'IV', 5 => 'V', 6 => 'VI', 7 => 'VII', 8 => 'VIII', 9 => 'IX' ],
           ];
    $res = '';
    foreach ($n2r as $p => $v) {
        $x = intdiv($n, $p);
        $n -= $p*$x;
        switch ($n) {
            case 45: $res .= ($n2r[$p][$x] ?? '').'VL'; return $res; break;
            case 49: $res .= ($n2r[$p][$x] ?? '').'IL'; return $res; break;
            case 95: $res .= ($n2r[$p][$x] ?? '').'VC'; return $res; break;
            case 99: $res .= ($n2r[$p][$x] ?? '').'IC'; return $res; break;
            default: $res .= $n2r[$p][$x] ?? '';
        }
        
    }
    return $res;  
}

 

Link to comment
Share on other sites

interesting. I can't believe that my code is even remotely similar to yours. I am not a very good programmer so it is nice to know that i did something correctly. I suppose that i am a bit too hard on myself. Really though, i am still trying to comprehend how i wrote code that is similar to your code. You are a pro and i am just a programmatic idiot trying to make a website. I guess i am slowly learning how to think programmatically. So progress is good 😀 but i don't let it go to my head. I got lucky this time and did something right.

I am going to get some coffee and get to work on my roman to decimal converter.

Link to comment
Share on other sites

update: so i used my decimal to roman numeral code inside of a loop in my roman to decimal code. All of the numbers passed, which means my code is not filtering standard roman numerals. Super! i changed an entry in the loop to a numeral that should be considered non standard and my code stopped the loop and displayed the invalid message. so the code is working. Then i used the decimal to roman code to produce an array of all of the standard roman numerals, then i used the var_export to create a copy of this good numerals array. I made a copy of the array produced in the roman to decimal converter that passed through the filtering process. I made a new php file named compare.php. I pasted both arrays into compare.php, then i created a loop that compares the values. If any value is different, then show the different value via echo. Continue the loop until it is finished. The result is a blank page, which confirms that good numerals are not filtered. Yippee!

However, i did notice that a nonstandard numeral still passes through my filter: xxxliiv. Now i permit nonstandard subtraction of numerals up to five, so iiv is okay. xxxl has not been handled. I have no filter for higher numeral subtractions. I think that i could make a rule that two non-standard subtractions should not occur in the same processed number. I am not yet sure if that idea works or not. But i can say that artificial intelligence could help me here. Imagine including my decimal to roman code inside of the same file as the roman to decimal code. I could calculate a good numeral based upon the total of the submitted numeral. Then compare the code and if the submitted code is different, then i will know that you are adding or subtracting to reach the nonstandard form of the decimal. Then i could check, i guess, powers of ten? 54 should have a fifty or L. Otherwise, you did something to reach 50 which is non standard. Thus, ixiiv should fail because the total is 14 which is between 10 and 20, yet the equation does not have a X (10). You did something strange to reach the number. If i can add such code to my current code, then i should have a splendid converter.

Link to comment
Share on other sites

yes it is 12. i made an erroneous mental calculation and i saw it after i posted.. i didn't want to log back in to correct it. ixiiv is still nonstandard and i intend to filter it out. I'm working on the code...

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.