Author Topic: Decimal to roman numbers converter  (Read 10518 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Decimal to roman numbers converter
« Reply #30 on: August 31, 2020, 04:37:45 pm »
Beyond 3999, Roman numerals involve multiplication.

For example, 4000 is IV M.  The IV represents 4, M represents 1000, so it's 4 * 1000.
5000 is V M.
6000 is VI M.

Notice the space between the multiplier and the 1000s digit, which means M M would be 1,000 * 1,000, or 1,000,000.  II M M, by this ruleset would be 2 * 1000 * 1000 = 2,000,000.

Note 2: In cases where spaces are hard to notice, multipliers often have a solid bar above them, such as:

__
IV   = 4 multiplier

_
V  = 5 multiplier

__
IVM = 4000

__
IVMI = 4001..  Ect..
« Last Edit: August 31, 2020, 04:38:59 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Juan Tamarit

  • Newbie
  • Posts: 53
    • View Profile
Re: Decimal to roman numbers converter
« Reply #31 on: August 31, 2020, 06:42:07 pm »
Guys, don't sweat it, V1.2 is complete and fully operational, GUI included

bplus's FOR i% = 1 to 3999 inspired me, so i used the first function to make a temporal roman and compare it with user input

Code: QB64: [Select]
  1. '--------------* Setup *--------------
  2. DATA "","I","II","III","IV","V","VI","VII","VIII","IX","","X","XX","XXX","XL","L","LX","LXX","LXXX","XC","","C","CC","CCC","CD","D","DC","DCC","DCCC","CM","","M","MM","MMM"
  3.  
  4. DIM SHARED resultPieces$(3, 9) '       ÍÍÍ»
  5. '                                         º
  6. FOR i% = 0 TO 3 '                         º
  7.     IF i% < 3 THEN '                      º
  8.         FOR ii% = 0 TO 9 '                º load DATA in
  9.             READ resultPieces$(i%, ii%) ' º this array
  10.         NEXT ii% '                        º
  11.     ELSE '                                º
  12.         FOR ii% = 0 TO 3 '                º
  13.             READ resultPieces$(i%, ii%) ' º
  14.         NEXT ii% '                        º
  15.     END IF '                              º
  16. NEXT i% '                              ÍÍͼ
  17.  
  18. SCREEN _NEWIMAGE(250, 96, 32) '        ÍÍÍ»
  19. CONST WHITE = _RGB32(255, 255, 255) '     º
  20. CONST YELLOW = _RGB32(255, 255, 0) '      º
  21. CONST RED = _RGB32(255, 0, 0) '           º set screen size
  22. CONST GREEN = _RGB32(0, 255, 0) '         º and colors
  23. CONST LIGHTGRAY = _RGB32(127, 127, 127) ' º
  24. CONST DARKGRAY = _RGB32(63, 63, 63) '  ÍÍͼ
  25.  
  26. _TITLE "Arabic/Roman Conversor"
  27.  
  28. DIM actualMenuWorking%
  29. DIM menuHighlight%
  30.  
  31.  
  32. DIM KeyPress$ ' key press by user
  33.  
  34. actualMenuWorking% = 0
  35. menuHighlight% = 1
  36.  
  37. '--------------* Program V1.2 *--------------
  38. sayHello
  39.  
  40.     DO '                         ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
  41.         KeyPress$ = INKEY$ '                             º get a key
  42.         _LIMIT 20 '                                      º from user
  43.         SELECT CASE actualMenuWorking% ' Í»              º
  44.             CASE 0: printMainMenu '       º              º
  45.             CASE 1: arabicToRoman '       º what do      º
  46.             CASE 2: romanToArabic '       º we do?       º
  47.             CASE -1: sayGoodbye '         º              º
  48.         END SELECT '                     ͼ              º
  49.     LOOP UNTIL KeyPress$ <> "" ' ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
  50.  
  51.     IF KeyPress$ = CHR$(13) THEN ' if ENTER pressed                   ÍÍÍÍÍ»
  52.         SELECT CASE menuHighlight% '                                       º
  53.             CASE 1: actualMenuWorking% = 1 '                               º
  54.             CASE 2: actualMenuWorking% = 2 '                               º analyze and react
  55.             CASE 3: actualMenuWorking% = -1 '                              º to user input for
  56.         END SELECT '                                                       º the MAIN MENU
  57.     ELSEIF KeyPress$ = CHR$(0) + "H" THEN ' if UP arrow pressed            º
  58.         IF menuHighlight% <> 1 THEN menuHighlight% = menuHighlight% - 1 '  º
  59.     ELSEIF KeyPress$ = CHR$(0) + "P" THEN ' if DOWN arrow pressed          º
  60.         IF menuHighlight% <> 3 THEN menuHighlight% = menuHighlight% + 1 '  º
  61.     ELSEIF KeyPress$ = CHR$(27) THEN '                                     º
  62.         menuHighlight% = 3 '                                               º
  63.     END IF '                                                          ÍÍÍÍͼ
  64.  
  65.  
  66.  
  67. '--------------* Functions *--------------
  68. FUNCTION turnIntegerToRoman$ (inputNumber%)
  69.  
  70.     numberAsString$ = LTRIM$(STR$(inputNumber%)) '                              turn number into s string, no spaces
  71.     IF inputNumber% > 0 AND inputNumber% < 4000 THEN '                          check if number inside range
  72.         digits% = LEN(numberAsString$) '                                        how many digits it has?
  73.         REDIM tmpArray%(digits%) '                                              make an integer array of that many digits long
  74.         REDIM subResult$(digits%) '                                             and another one, but string type, forbuilding the result
  75.         FOR i% = 0 TO digits% - 1 '                                             cicle for every digit
  76.             tmpArray%(i%) = VAL(MID$(numberAsString$, digits% - i%, 1)) '       save in the integer array the value of the digit
  77.             subResult$(i%) = resultPieces$(i%, tmpArray%(i%)) '                 in the string array save the piece according with value and
  78.             result$ = subResult$(i%) + result$ '                                keep building result with pieces untill finish cicling
  79.         NEXT i%
  80.         COLOR GREEN '                                                           since numbar was in range we are allowed to send a good answer
  81.         turnIntegerToRoman$ = result$ '                                         wich we just built
  82.     ELSE '                                                                      but if number was not in range
  83.         COLOR RED '                                                             something bad happenen, so red color
  84.         turnIntegerToRoman$ = "I can't convert " + numberAsString$ '            and we warn about it
  85.     END IF
  86.  
  87.  
  88. '- - - - - - - - - - - - - - - - - - - - - -
  89. FUNCTION turnRomanToInteger$ (inputRoman$)
  90.  
  91.     tmpRomanToCompare$ = "" '                                                   we make a temporary variable to place built romans to compare with user input
  92.  
  93.     FOR i% = 3999 TO 1 STEP -1 '                                                we gonna check all possible numbers
  94.         tmpRomanToCompare$ = turnIntegerToRoman$(i%) '                          make a temporal roman number
  95.         IF tmpRomanToCompare$ = inputRoman$ THEN '                              and compare to user input
  96.             COLOR GREEN '                                                       if its the same is all good
  97.             turnRomanToInteger$ = LTRIM$(STR$(i%)) '                            we can send the result as string, no spaces
  98.             EXIT FUNCTION '                                                     and leave here
  99.         END IF
  100.     NEXT i%
  101.  
  102.     COLOR RED '                                                                 but if no coincidence was made something is wrong
  103.     turnRomanToInteger$ = "Not a roman!" '                                      we should warn it
  104.  
  105.  
  106. '--------------* Subroutines *--------------
  107. SUB sayHello ()
  108.  
  109.     helloMessage1$ = "       Hello my master"
  110.     helloMessage2$ = "  Order me and i will obey..."
  111.  
  112.     COLOR GREEN
  113.  
  114.     i% = 0 '                                                   ÍÍÍÍ»
  115.     DO '                                                           º
  116.         _DELAY .05 '                                               º
  117.         i% = i% + 1 '                                              º print helloMessage1$
  118.         buildingMessage$ = LEFT$(helloMessage1$, i%) + CHR$(219) ' º character by character
  119.         LOCATE 3, 1 '                                              º and erease the cursor
  120.         PRINT buildingMessage$ '                                   º
  121.     LOOP UNTIL LEN(buildingMessage$) = LEN(helloMessage1$) + 1 '   º
  122.     LOCATE CSRLIN - 1, LEN(helloMessage1$) + 1: PRINT " " '    ÍÍÍͼ
  123.  
  124.     i% = 0 '                                                   ÍÍÍÍ»
  125.     DO '                                                           º
  126.         _DELAY .05 '                                               º
  127.         i% = i% + 1 '                                              º print helloMessage2$
  128.         buildingMessage$ = LEFT$(helloMessage2$, i%) + CHR$(219) ' º character by character
  129.         LOCATE 4, 1 '                                              º and erease the cursor
  130.         PRINT buildingMessage$ '                                   º
  131.     LOOP UNTIL LEN(buildingMessage$) = LEN(helloMessage2$) + 1 '   º
  132.     LOCATE CSRLIN - 1, LEN(helloMessage2$) + 1: PRINT " " '    ÍÍÍͼ
  133.  
  134.     SLEEP 2
  135.  
  136.  
  137. '- - - - - - - - - - - - - - - - - - - - - -
  138. SUB printMainMenu ()
  139.  
  140.     SHARED menuHighlight%
  141.  
  142.     CLS
  143.  
  144.     LOCATE 1, 1 '                                          ÍÍÍ»
  145.     COLOR WHITE '                                             º Title
  146.     PRINT "     Roman/Arabic Conversor"; '                 ÍÍͼ
  147.     LOCATE 2, 1 '                                          ÍÍÍ»
  148.     PRINT SPACE$(5);: PRINT STRING$(22, CHR$(223)); '      ÍÍͼ Underline
  149.  
  150.     IF menuHighlight% = 1 THEN '                           ÍÍÍ»
  151.         COLOR YELLOW '                                        º
  152.         LOCATE 3, 7 '                                         º
  153.         PRINT CHR$(26);: PRINT SPACE$(16);: PRINT CHR$(27); ' º
  154.     ELSE '                                                    º Arabic  Roman
  155.         COLOR DARKGRAY '                                      º
  156.     END IF '                                                  º
  157.     LOCATE 3, 9 '                                             º
  158.     PRINT "Arabic  Roman"; '                              ÍÍͼ
  159.  
  160.     IF menuHighlight% = 2 THEN '                           ÍÍÍ»
  161.         COLOR YELLOW '                                        º
  162.         LOCATE 4, 7 '                                         º
  163.         PRINT CHR$(26);: PRINT SPACE$(16);: PRINT CHR$(27); ' º
  164.     ELSE '                                                    º Roman  Arabic
  165.         COLOR DARKGRAY '                                      º
  166.     END IF '                                                  º
  167.     LOCATE 4, 9 '                                             º
  168.     PRINT "Roman  Arabic"; '                              ÍÍͼ
  169.  
  170.     IF menuHighlight% = 3 THEN '                           ÍÍÍ»
  171.         COLOR YELLOW '                                        º
  172.         LOCATE 5, 12 '                                        º
  173.         PRINT CHR$(26);: PRINT SPACE$(6);: PRINT CHR$(27); '  º
  174.     ELSE '                                                    º Exit
  175.         COLOR DARKGRAY '                                      º
  176.     END IF '                                                  º
  177.     LOCATE 5, 14 '                                            º
  178.     PRINT "Exit"; '                                        ÍÍͼ
  179.  
  180.     COLOR WHITE '                                          ÍÍÍ»
  181.     LOCATE 6, 1 '                                             º Instructions
  182.     PRINT " UP-DOWN select / ENTER choose"; '              ÍÍͼ
  183.  
  184.     _DISPLAY
  185.  
  186.  
  187. '- - - - - - - - - - - - - - - - - - - - - -
  188. SUB arabicToRoman ()
  189.  
  190.     SHARED actualMenuWorking%
  191.  
  192.     subInput$ = ""
  193.     num% = 0
  194.  
  195.     DO
  196.         DO '                         ÍÍ»
  197.             CLS '                      º
  198.             COLOR WHITE '                               ÍÍÍÍ»
  199.             LOCATE 1, 1 '                                   º istructions
  200.             PRINT "Give me a number from 1 to 3999" '       º for user
  201.             PRINT "     Press ESC to go back" '         ÍÍÍͼ
  202.             PRINT "          > ";: PRINT subInput$ + CHR$(95) ' what user writes
  203.             PRINT
  204.             PRINT num%; "= "; turnIntegerToRoman$(num%); ' what user want's to see
  205.             KeyPress$ = INKEY$ '       º get a key
  206.             _LIMIT 20 '                º from user
  207.             _DISPLAY '                 º
  208.         LOOP UNTIL KeyPress$ <> "" ' Íͼ
  209.  
  210.         'NUMBERS
  211.         IF (ASC(KeyPress$) > 47 AND ASC(KeyPress$) < 58) THEN 'if NUMBER pressed and the subInput$ is not longer
  212.             IF LEN(subInput$) < 4 THEN subInput$ = subInput$ + KeyPress$ '    than 4 then increase the subInput$
  213.  
  214.             'BACKSPACE
  215.         ELSEIF KeyPress$ = CHR$(8) THEN '                   if BACKSPACE pressed and subInput ain't null
  216.             IF subInput$ <> "" THEN subInput$ = LEFT$(subInput$, LEN(subInput$) - 1) 'one less character
  217.  
  218.             ' ENTER
  219.         ELSEIF KeyPress$ = CHR$(13) THEN '  if ENTER pressed and
  220.             IF subInput$ <> "" THEN '       subInput$ ain't null then
  221.                 num% = VAL(subInput$) '     turn to a value and save it to num%
  222.                 subInput$ = "" '            and clear subInput$
  223.             END IF
  224.         END IF
  225.  
  226.         'ESC
  227.     LOOP UNTIL KeyPress$ = CHR$(27)
  228.     actualMenuWorking% = 0
  229.  
  230.  
  231. '- - - - - - - - - - - - - - - - - - - - - -
  232. SUB romanToArabic ()
  233.  
  234.     SHARED actualMenuWorking%
  235.  
  236.     subInput$ = ""
  237.     lastInput$ = "I"
  238.  
  239.     DO
  240.         DO '                         ÍÍ»
  241.             CLS '                      º
  242.             COLOR WHITE '                               ÍÍÍÍ»
  243.             LOCATE 1, 1 '                                   º istructions
  244.             PRINT "Give me a number from 1 to 3999" '       º for user
  245.             PRINT "     Press ESC to go back" '         ÍÍÍͼ
  246.             PRINT "      > ";: PRINT subInput$ + CHR$(95) ' what user writes
  247.             PRINT
  248.             PRINT " "; lastInput$; " = "; turnRomanToInteger$(lastInput$); ' what user want's to see
  249.             KeyPress$ = INKEY$ '       º get a key
  250.             _LIMIT 20 '                º from user
  251.             _DISPLAY '                 º
  252.         LOOP UNTIL KeyPress$ <> "" ' Íͼ
  253.  
  254.         'LETTERS
  255.         IF LEN(subInput$) < 15 THEN ' if roman not longer than 15 (MMMDCCCLXXXVIII)
  256.             SELECT CASE ASC(KeyPress$) ' only valid letters
  257.                 CASE 73 OR 105: subInput$ = subInput$ + KeyPress$ ' I
  258.                 CASE 86 OR 118: subInput$ = subInput$ + KeyPress$ ' V
  259.                 CASE 88 OR 120: subInput$ = subInput$ + KeyPress$ ' X
  260.                 CASE 76 OR 108: subInput$ = subInput$ + KeyPress$ ' L
  261.                 CASE 67 OR 99: subInput$ = subInput$ + KeyPress$ '  C
  262.                 CASE 68 OR 100: subInput$ = subInput$ + KeyPress$ ' D
  263.                 CASE 77 OR 109: subInput$ = subInput$ + KeyPress$ ' M
  264.             END SELECT
  265.         END IF
  266.  
  267.         'BACKSPACE
  268.         IF KeyPress$ = CHR$(8) THEN ' if BACKSPACE pressen and subInput ain't null
  269.             IF subInput$ <> "" THEN subInput$ = LEFT$(subInput$, LEN(subInput$) - 1) 'one less character
  270.  
  271.             ' ENTER
  272.         ELSEIF KeyPress$ = CHR$(13) THEN '  if ENTER pressed and
  273.             IF subInput$ <> "" THEN '       subInput$ ain't null then
  274.                 lastInput$ = subInput$ '    do as user says
  275.                 subInput$ = "" '            and clear subInput$
  276.             END IF
  277.         END IF
  278.  
  279.         subInput$ = UCASE$(subInput$) ' in case user dosn't use uppers
  280.  
  281.         'ESC
  282.     LOOP UNTIL KeyPress$ = CHR$(27)
  283.     actualMenuWorking% = 0
  284.  
  285.  
  286. '- - - - - - - - - - - - - - - - - - - - - -
  287. SUB sayGoodbye ()
  288.  
  289.     CLS
  290.  
  291.     goodbyeMessage$ = "Have a nice day!"
  292.  
  293.     COLOR RED '                                              ÍÍÍ»
  294.     LOCATE 3, 7 '                                               º
  295.     PRINT CHR$(3) '                                             º Hearts
  296.     LOCATE 3, 26 '                                              º
  297.     PRINT CHR$(3) '                                          ÍÍͼ
  298.  
  299.     COLOR GREEN '                                            ÍÍÍ»
  300.     i% = 0 '                                                    º
  301.     DO '                                                        º print goodbyeMessage$
  302.         _DELAY .05 '                                            º character by character
  303.         i% = i% + 1 '                                           º
  304.         buildingMessage$ = LEFT$(goodbyeMessage$, i%) '         º
  305.         LOCATE 3, 9 '                                           º
  306.         PRINT buildingMessage$ '                                º
  307.         _DISPLAY '                                              º
  308.     LOOP UNTIL LEN(buildingMessage$) = LEN(goodbyeMessage$) 'ÍÍͼ
  309.  
  310.     SLEEP 2 '                                                ÍÍÍ»
  311.     SYSTEM '                                                 ÍÍͼ Wait & kill
  312.  

Offline Juan Tamarit

  • Newbie
  • Posts: 53
    • View Profile
Re: Decimal to roman numbers converter
« Reply #32 on: August 31, 2020, 07:23:45 pm »
I see u guys wondering about numbers beyond 3999... indeed, for a value of 4000 it should say IV with a line over it. I could find a way to do this, but i feel satisfied with the actual result, it accomplished my expectations.
Thanks to everyone for the warm welcome, pacient feedback and great ideas! I'll keep thinking in the next proyect! =)
Of course, if anyone want´s to try to make the code smaller or finds another way to do this it will be nicely welcome
Cheers, good people!

FellippeHeitor

  • Guest
Re: Decimal to roman numbers converter
« Reply #33 on: August 31, 2020, 07:27:57 pm »
Very nice minimalistic interface, and sweet good-bye message. Good job!

Offline Juan Tamarit

  • Newbie
  • Posts: 53
    • View Profile
Re: Decimal to roman numbers converter
« Reply #34 on: August 31, 2020, 07:44:15 pm »
Wow! You Felipe? The one of the youtube/radio program? Thank you very much for develop the QB64! I find it to be a perfect vehicle for my ideas! Count on me if you need help with something, i'll try to squeeze my head.

And thanks Terry too! I can say how much his site has tought me (along some discipline from me). I still have to finish the course! i just reached task 14 for audio, hehehe, we could add some BEEPS to the converter ahahahah XD

I was think in a moment of random frecuencies while "thinking" the answer... i avoided for the moment, targeting staright to the missing function.

What i still will like to do is the "load-DATA-only-for-the-function-then clear-it". I know this program is not memory consuming, but if somebody wants to use, say in a text to voice program i want t make sure things are in it's place. (Interesting: voice finds a valid roman and "read" it as integer, but that's for advancer programmers who works on AI's, right?)

FellippeHeitor

  • Guest
Re: Decimal to roman numbers converter
« Reply #35 on: August 31, 2020, 08:56:58 pm »
Just another cog in the machine, we're all fans of Galleon's great work.

Glad to have you in the community. What's your history with programming so far?

Offline Juan Tamarit

  • Newbie
  • Posts: 53
    • View Profile
Re: Decimal to roman numbers converter
« Reply #36 on: August 31, 2020, 09:48:29 pm »
Glad to have you in the community. What's your history with programming so far?

Glad to be here! =) A i said i'm a chemistry technician, i had a veeeryyy basic aproach to programming in the general curriculum (we used QBASIC at the school! in 2001), so i understood the concept of an IF statement and 2 or 3 things more. No more programming in my life UNTIL some years ago electronics came in as a hobby (some components still there on the shelve) and i started on a forum (that's why i'm here). Electronics took me to Arduino. After a single succeded proyect (but a lot of learning both in programming an electronics) no more programming in my life UNTIL i wanted to make my game, i started with GameMaker 8.1, never succeded in my target, but still a lot of learning and exploration. I decided to try another way, so i looked back to my start... and QB64 and St Terrie's appeard. After 14 chapters of course an idea came out (the arabic>roman). I did it and decided to check with others (as first post says), the rest is on the posts and now with my first program from scratch just built.

And here i am now, bro =) On the seventh day i rested XD

'------------* EDIT *-----------

Question: in my function turnIntegerToRoman$() i use REDIM, but i was thinking if thats correct or should just be DIM, or if no need to declarate (i think they need it because they are arrays). By the way, i can't place an array inside a TYPE...END TYPE, isn't it?


« Last Edit: August 31, 2020, 10:23:36 pm by Juan Tamarit »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Decimal to roman numbers converter
« Reply #37 on: August 31, 2020, 10:22:32 pm »
Yes nice! Table lookup was so much easier to check if Roman was legit, thanks for idea Steve.

Offline euklides

  • Forum Regular
  • Posts: 128
    • View Profile
Re: Decimal to roman numbers converter
« Reply #38 on: September 01, 2020, 03:09:05 am »
I use since years this little program:

(Put a value in 'anr')


ANR = 2020
GOSUB romain
PRINT rom$
END

romain: aro# = ANR: IF aro# < 0 THEN rom$ = "Zéro": RETURN
IF aro# > 3999 THEN rom$ = "????": RETURN
IF aro# >= 3000 THEN rom$ = rom$ + "MMM": aro# = aro# - 3000
IF aro# >= 2000 THEN rom$ = rom$ + "MM": aro# = aro# - 2000
IF aro# >= 1000 THEN rom$ = rom$ + "M": aro# = aro# - 1000
IF aro# >= 900 THEN rom$ = rom$ + "CM": aro# = aro# - 900
IF aro# >= 800 THEN rom$ = rom$ + "DCCC": aro# = aro# - 800
IF aro# >= 700 THEN rom$ = rom$ + "DCC": aro# = aro# - 700
IF aro# >= 600 THEN rom$ = rom$ + "DC": aro# = aro# - 600
IF aro# >= 500 THEN rom$ = rom$ + "D": aro# = aro# - 500
IF aro# >= 400 THEN rom$ = rom$ + "CD": aro# = aro# - 400
IF aro# >= 300 THEN rom$ = rom$ + "CCC": aro# = aro# - 300
IF aro# >= 200 THEN rom$ = rom$ + "CC": aro# = aro# - 200
IF aro# >= 100 THEN rom$ = rom$ + "C": aro# = aro# - 100
IF aro# >= 90 THEN rom$ = rom$ + "XC": aro# = aro# - 90
IF aro# >= 80 THEN rom$ = rom$ + "LXXX": aro# = aro# - 80
IF aro# >= 70 THEN rom$ = rom$ + "LXX": aro# = aro# - 70
IF aro# >= 60 THEN rom$ = rom$ + "LX": aro# = aro# - 60
IF aro# >= 50 THEN rom$ = rom$ + "L": aro# = aro# - 50
IF aro# >= 40 THEN rom$ = rom$ + "XL": aro# = aro# - 40
IF aro# >= 30 THEN rom$ = rom$ + "XXX": aro# = aro# - 30
IF aro# >= 20 THEN rom$ = rom$ + "XX": aro# = aro# - 20
IF aro# >= 10 THEN rom$ = rom$ + "X": aro# = aro# - 10
IF aro# >= 9 THEN rom$ = rom$ + "IX": aro# = aro# - 9
IF aro# >= 8 THEN rom$ = rom$ + "VIII": aro# = aro# - 8
IF aro# >= 7 THEN rom$ = rom$ + "VII": aro# = aro# - 7
IF aro# >= 6 THEN rom$ = rom$ + "VI": aro# = aro# - 6
IF aro# >= 5 THEN rom$ = rom$ + "V": aro# = aro# - 5
IF aro# >= 4 THEN rom$ = rom$ + "IV": aro# = aro# - 4
IF aro# >= 3 THEN rom$ = rom$ + "III": aro# = aro# - 3
IF aro# >= 2 THEN rom$ = rom$ + "II": aro# = aro# - 2
IF aro# >= 1 THEN rom$ = rom$ + "I": aro# = aro# - 1
RETURN
Why not yes ?

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Decimal to roman numbers converter
« Reply #39 on: September 01, 2020, 03:24:43 am »
Good program Juan!
Here is my approach (I'm using Steve idea for number greater than 3999):
Code: QB64: [Select]
  1. _TITLE "Arabic To Roman : By Ashish"
  2. TYPE dict
  3.     c AS STRING * 2 'roman literal
  4.     n AS _UNSIGNED INTEGER 'its equivalent in arabic
  5.  
  6. DIM SHARED roman_literal(12) AS dict
  7. FOR i = 0 TO UBOUND(roman_literal) 'store the value in the array
  8.     READ roman_literal(i).n, roman_literal(i).c
  9. q~& = -1
  10. PRINT "Arabic to Roman Converter [ 1 to "; q~&; "] : By Ashish"
  11.     INPUT ">", num
  12.     PRINT ArabicToRoman(num)
  13. LOOP UNTIL num = 0
  14. DATA 1,"I",4,"IV",5,"V",9,"IX",10,"X",40,"XL",50,"L",90,"XC",100,"C",400,"CD",500,"D",900,"CM",1000,"M"
  15.  
  16. FUNCTION ArabicToRoman$ (n~&)
  17.     IF n~& >= 4000 THEN
  18.         k~& = INT(n~& / 1000)
  19.         ArabicToRoman$ = ArabicToRoman$(k~&) + " " + ArabicToRoman$(n~& - (k~& - 1) * 1000)
  20.     ELSE
  21.         IF n~& = 0 THEN PRINT "invalid": EXIT FUNCTION
  22.         ArabicToRoman$ = __internal_convertArabicToRoman(n~&)
  23.     END IF
  24. FUNCTION __internal_convertArabicToRoman$ (n~&)
  25.     i~& = UBOUND(roman_literal)
  26.     x~& = n~&
  27.     DO
  28.         IF x~& >= roman_literal(i~&).n AND x~& < 4 * roman_literal(i~&).n THEN
  29.             p~& = INT(x~& / roman_literal(i~&).n)
  30.             __internal_convertArabicToRoman$ = __internal_convertArabicToRoman$ + strRepeat(p~&, roman_literal(i~&).c)
  31.             x~& = x~& - (roman_literal(i~&).n * p~&)
  32.         ELSE
  33.             i~& = i~& - 1 'move below in the array
  34.         END IF
  35.     LOOP UNTIL x~& = 0
  36.     s = RTRIM$(s)
  37.     FOR i~& = 1 TO n
  38.         strRepeat$ = strRepeat$ + s
  39.     NEXT
  40.  
« Last Edit: September 01, 2020, 11:43:13 am by Ashish »
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Decimal to roman numbers converter
« Reply #40 on: September 01, 2020, 11:37:41 am »
Hi @Ashish

Code: QB64: [Select]
  1.     INPUT ">", num
  2.     PRINT ArabicToRoman(num)
  3. LOOP UNTIL num = 0
  4.  

Need to DIM num as _UNSIGNED LONG so some fool who types in the top limit wont get an "invalid" message.

I am still checking out how you handle conversions, very interesting.


Hi @euklides

Code: QB64: [Select]
  1. IF aro# < 0 THEN rom$ = "Zéro": RETURN  
Might want <= 0 because absolutely nothing gets returned for aro# = 0

I like your straight forward no nonsense approach!

Man it is so interesting to see the different approaches to same problem!
« Last Edit: September 01, 2020, 11:48:12 am by bplus »

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Decimal to roman numbers converter
« Reply #41 on: September 01, 2020, 11:44:28 am »
@bplus thanks. I have just edited it. :)
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Decimal to roman numbers converter
« Reply #42 on: September 01, 2020, 12:16:47 pm »
I modified @euklides for multiple testing of romain GOSUB: for handy FUNCTION and to do multiple tests:
Code: QB64: [Select]
  1. 'ANR = 2020 'Euklides vers 2020-09-01 https://www.qb64.org/forum/index.php?topic=2960.msg122293#msg122293
  2. 'GOSUB romain
  3. 'PRINT rom$
  4. 'END
  5.  
  6. '>>> b+ mod to convert to handy Function  2020-09-01
  7.     PRINT: PRINT "0 or less quits"
  8.     INPUT "Enter 1 to 3999 a number to convert to Roman: "; anr
  9.     PRINT "romain returned "; romain$(anr)
  10.     IF anr <= 0 THEN END
  11.  
  12. FUNCTION romain$ (anr)
  13.     aro# = anr 'copy anr so it's not changed
  14.     IF aro# <= 0 THEN romain$ = "Zéro": EXIT FUNCTION '<<< add = to < for compare
  15.     IF aro# > 3999 THEN romain$ = "????": EXIT FUNCTION
  16.     IF aro# >= 3000 THEN rom$ = rom$ + "MMM": aro# = aro# - 3000
  17.     IF aro# >= 2000 THEN rom$ = rom$ + "MM": aro# = aro# - 2000
  18.     IF aro# >= 1000 THEN rom$ = rom$ + "M": aro# = aro# - 1000
  19.     IF aro# >= 900 THEN rom$ = rom$ + "CM": aro# = aro# - 900
  20.     IF aro# >= 800 THEN rom$ = rom$ + "DCCC": aro# = aro# - 800
  21.     IF aro# >= 700 THEN rom$ = rom$ + "DCC": aro# = aro# - 700
  22.     IF aro# >= 600 THEN rom$ = rom$ + "DC": aro# = aro# - 600
  23.     IF aro# >= 500 THEN rom$ = rom$ + "D": aro# = aro# - 500
  24.     IF aro# >= 400 THEN rom$ = rom$ + "CD": aro# = aro# - 400
  25.     IF aro# >= 300 THEN rom$ = rom$ + "CCC": aro# = aro# - 300
  26.     IF aro# >= 200 THEN rom$ = rom$ + "CC": aro# = aro# - 200
  27.     IF aro# >= 100 THEN rom$ = rom$ + "C": aro# = aro# - 100
  28.     IF aro# >= 90 THEN rom$ = rom$ + "XC": aro# = aro# - 90
  29.     IF aro# >= 80 THEN rom$ = rom$ + "LXXX": aro# = aro# - 80
  30.     IF aro# >= 70 THEN rom$ = rom$ + "LXX": aro# = aro# - 70
  31.     IF aro# >= 60 THEN rom$ = rom$ + "LX": aro# = aro# - 60
  32.     IF aro# >= 50 THEN rom$ = rom$ + "L": aro# = aro# - 50
  33.     IF aro# >= 40 THEN rom$ = rom$ + "XL": aro# = aro# - 40
  34.     IF aro# >= 30 THEN rom$ = rom$ + "XXX": aro# = aro# - 30
  35.     IF aro# >= 20 THEN rom$ = rom$ + "XX": aro# = aro# - 20
  36.     IF aro# >= 10 THEN rom$ = rom$ + "X": aro# = aro# - 10
  37.     IF aro# >= 9 THEN rom$ = rom$ + "IX": aro# = aro# - 9
  38.     IF aro# >= 8 THEN rom$ = rom$ + "VIII": aro# = aro# - 8
  39.     IF aro# >= 7 THEN rom$ = rom$ + "VII": aro# = aro# - 7
  40.     IF aro# >= 6 THEN rom$ = rom$ + "VI": aro# = aro# - 6
  41.     IF aro# >= 5 THEN rom$ = rom$ + "V": aro# = aro# - 5
  42.     IF aro# >= 4 THEN rom$ = rom$ + "IV": aro# = aro# - 4
  43.     IF aro# >= 3 THEN rom$ = rom$ + "III": aro# = aro# - 3
  44.     IF aro# >= 2 THEN rom$ = rom$ + "II": aro# = aro# - 2
  45.     IF aro# >= 1 THEN rom$ = rom$ + "I": aro# = aro# - 1
  46.     romain$ = rom$
  47.  

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Decimal to roman numbers converter
« Reply #43 on: September 01, 2020, 04:23:48 pm »
@Ashish has beautifully condensed Euklides method AND extended the notation beyond 3999.

Here I condensed Ashish code to one single independent Function of 29 lines AND modified the notation of the Roman numeral multipliers. Since we can't put a bar over the letters (easily, nor repeat it typing on the keyboard), I propose using lower case letters and separating the multiplier from the final digits with a * instead of a space. That way one long number can be easily distinguished from the one next to it or a whole string of long numbers.

Code: QB64: [Select]
  1. _TITLE "Roman MOD post Ashish" 'b+ 2020-09-01 combine Ashish down to one independent Function 29 lines!
  2. q~& = -1
  3. PRINT "Arabic to Roman Converter [ 1 to "; q~&; "] : By Ashish"
  4.     INPUT "Enter Arabic to convert to Roman >", num
  5.     PRINT A2R$(num)
  6. LOOP UNTIL num = 0
  7. FUNCTION A2R$ (nn AS _UNSIGNED LONG) 'Arabic positive integer to Roman string
  8.     STATIC d(12) AS _UNSIGNED LONG, c(12) AS STRING
  9.     IF d(0) = 0 THEN ' load n and c arrays
  10.         FOR ub = 0 TO 12
  11.             READ d(ub), c(ub)
  12.         NEXT
  13.     END IF
  14.     n = nn 'private copy of nn because we will be recursive
  15.     IF n >= 4000 THEN
  16.         k = INT(n / 1000)
  17.         A2R$ = LCASE$(A2R$(k)) + "*" + A2R$(n - (k - 1) * 1000)
  18.     ELSE
  19.         IF n = 0 THEN PRINT "invalid": EXIT FUNCTION
  20.         ub = 12: x = n
  21.         DO ' *** Ashish uses same method as Euklides but condensed beautifully here ***
  22.             IF x >= d(ub) AND x < 4 * d(ub) THEN ' x falls between which two decimal amounts?
  23.                 p = INT(x / d(ub)): s = "" 'setup to copy Roman symbol(s) p times
  24.                 FOR i = 1 TO p: s = s + c(ub): NEXT 'string copy
  25.                 A2R$ = A2R$ + s: x = x - d(ub) * p
  26.             ELSE
  27.                 ub = ub - 1 'move index ub down
  28.             END IF
  29.         LOOP UNTIL x = 0
  30.     END IF
  31.     EXIT FUNCTION 'below is nice condensed data Ashish uses same method as Euklides but condensed beautifully
  32.     DATA 1,"I",4,"IV",5,"V",9,"IX",10,"X",40,"XL",50,"L",90,"XC",100,"C",400,"CD",500,"D",900,"CM",1000,"M"
  33.  





« Last Edit: September 01, 2020, 05:00:43 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Decimal to roman numbers converter
« Reply #44 on: September 01, 2020, 10:03:06 pm »
Revised and extended Roman$ Function that converts either way handling extended expressions to limit of _UNSIGNED LONG type. I developed this using lower case and * notation. Then when working properly, I converted to all UCASE$ and space between extensions.

Code: QB64: [Select]
  1. _TITLE "Roman$ Function Test and Demo" ' b+ 2020-09-01 revise Roman SUB to latest changes at forum
  2. DIM q~&, output$, num AS _UNSIGNED LONG, test$
  3. q~& = -1: num = 4294967295 'quick test of big number limit
  4. PRINT num; "= "; Roman$(STR$(num))
  5. '         4294967295    4294967295   'limit
  6. FOR num = 4200000000 TO 4200000020
  7.     output$ = Roman$(STR$(num))
  8.     test$ = Roman$(output$)
  9.     LOCATE CSRLIN, 1: PRINT num;
  10.     LOCATE CSRLIN, 20: PRINT output$;
  11.     LOCATE CSRLIN, 50: PRINT test$
  12.     IF num <> VAL(test$) THEN BEEP: SLEEP
  13.     PRINT " Testing conversion of numbers 0 to"; q~&; " to or from Roman Numerals >"
  14.     INPUT " Enter a string to test "; test$
  15.     output$ = Roman$(test$)
  16.     PRINT " The Roman SUB returned: "; output$
  17.     PRINT
  18. LOOP UNTIL test$ = ""
  19.  
  20. FUNCTION Roman$ (instrg$) ' for extended Roman Numeral conversions
  21.     STATIC d(12) AS _UNSIGNED LONG, c(12) AS STRING, R$(1 TO 3999)
  22.     DIM pd AS INTEGER, pr AS INTEGER, lastpd AS INTEGER, lastpr AS INTEGER
  23.     IF d(0) = 0 THEN ' load n and c arrays
  24.         FOR ub = 0 TO 12
  25.             READ d(ub), c(ub)
  26.         NEXT
  27.         FOR i = 1 TO 3999
  28.             ub = 12: x = i: conv = ""
  29.             DO ' *** Ashish uses same method as Euklides but condensed beautifully here ***
  30.                 IF x >= d(ub) AND x < 4 * d(ub) THEN ' x falls between which two decimal amounts?
  31.                     p = INT(x / d(ub)): s = "" 'setup to copy Roman symbol(s) p times
  32.                     FOR j = 1 TO p: s = s + c(ub): NEXT 'string copy
  33.                     conv = conv + s: x = x - d(ub) * p
  34.                 ELSE
  35.                     ub = ub - 1 'move index ub down
  36.                 END IF
  37.             LOOP UNTIL x = 0
  38.             R$(i) = conv
  39.         NEXT
  40.     END IF 'end of setup, one time only
  41.     s = _TRIM$(UCASE$(instrg$))
  42.     IF s = "" OR s = "0" THEN Roman$ = "Error: nada": EXIT FUNCTION 'handle nothing
  43.     FOR i = 1 TO LEN(s) ' character checkup
  44.         pd = INSTR("0123456789", MID$(s, i, 1)): pr = INSTR(" MDCLXVI", MID$(s, i, 1))
  45.         IF pd = 0 AND pr = 0 THEN Roman$ = "Error: unknown character.": EXIT SUB 'handle wrong alpha
  46.         IF i > 1 THEN 'check for mixed messages
  47.             IF (lastpd = 0 AND pd > 0) OR (lastpr = 0 AND pr > 0) THEN Roman$ = "Error: digits mixed with letters.": EXIT SUB
  48.         END IF
  49.         lastpd = pd: lastpr = pr
  50.     NEXT
  51.     v = VAL(s) 'is s a number or a Roman Numeral string?
  52.     IF v = 0 THEN
  53.         REDIM vs(0) AS STRING ' vs for value strings
  54.         Split s, " M", vs() '   Handy Split for parsing *M sections
  55.         conv = "" '             Build our string on this variable (reusing)
  56.         FOR j = 0 TO UBOUND(vs)
  57.             pd = 0 'reuse an integer for found match
  58.             FOR i = 1 TO 3999
  59.                 IF R$(i) = vs(j) THEN ' When stringing together numbers after first set need 0 fillers.
  60.                     IF j > 0 THEN conv = conv + RIGHT$("000" + _TRIM$(STR$(i)), 3) ELSE conv = conv + _TRIM$(STR$(i))
  61.                     pd = 1: EXIT FOR 'pd indeicates a match was found
  62.                 END IF
  63.             NEXT
  64.             IF pd <> 1 THEN ' No match found, maybe this is empty 000 space?
  65.                 IF vs(j) = "" THEN conv = conv + "000" ELSE Roman$ = "Error: Invalid Roman Numeral? string.": EXIT FUNCTION
  66.             END IF
  67.         NEXT
  68.         Roman$ = conv
  69.     ELSEIF v >= 4000 THEN ' Beyond our Roman String Table
  70.         k = INT(v / 1000)
  71.         Roman$ = Roman$(STR$(k)) + " " + Roman$(STR$(v - (k - 1) * 1000)) ' Go recursive until v < 4000
  72.     ELSE
  73.         Roman$ = R$(v) 'Table lookup
  74.     END IF
  75.     EXIT SUB 'below is nice condensed data Ashish uses same method as Euklides but condensed beautifully
  76.     DATA 1,"I",4,"IV",5,"V",9,"IX",10,"X",40,"XL",50,"L",90,"XC",100,"C",400,"CD",500,"D",900,"CM",1000,"M"
  77.  
  78. SUB Split (SplitMeString AS STRING, delim AS STRING, loadMeArray() AS STRING)
  79.     DIM curpos AS LONG, arrpos AS LONG, LD AS LONG, dpos AS LONG 'fix use the Lbound the array already has
  80.     curpos = 1: arrpos = LBOUND(loadMeArray): LD = LEN(delim)
  81.     dpos = INSTR(curpos, SplitMeString, delim)
  82.     DO UNTIL dpos = 0
  83.         loadMeArray(arrpos) = MID$(SplitMeString, curpos, dpos - curpos)
  84.         arrpos = arrpos + 1
  85.         IF arrpos > UBOUND(loadMeArray) THEN REDIM _PRESERVE loadMeArray(LBOUND(loadMeArray) TO UBOUND(loadMeArray) + 1000) AS STRING
  86.         curpos = dpos + LD
  87.         dpos = INSTR(curpos, SplitMeString, delim)
  88.     LOOP
  89.     loadMeArray(arrpos) = MID$(SplitMeString, curpos)
  90.     REDIM _PRESERVE loadMeArray(LBOUND(loadMeArray) TO arrpos) AS STRING 'get the ubound correct
  91.  
  92.