|
Post by bplus on Aug 14, 2024 8:49:24 GMT
Convert to Roman Numerals and back again to Number
_Title "Roman Numerals Converter mod 4 2024-08-13" Dim Shared Value$, Symbol$ Value$ = "1000 900 500 400 100 90 50 40 10 9 5 4 1" Symbol$ = " MCM DCD CXC LXL XIX VIV I" $Console:Only For i = 1 To 4000 r$ = Romanize$(i): C$ = String$(15, " "): n% = Numeralize%(r$): Mid$(C$, 1, Len(r$)) = r$ Print i, C$; n%: If i <> n% Then Beep: Sleep ' keep us honest :) Next Function Romanize$ (number As Integer) If number < 1 Or number > 3999 Then Romanize$ = "Out of Range": Exit Function num% = number For i% = 1 To 13 While num% >= Val(Mid$(Value$, (i% - 1) * 4 + 1, 4)) romanNum$ = romanNum$ + _Trim$(Mid$(Symbol$, (i% - 1) * 2 + 1, 2)) num% = num% - Val(Mid$(Value$, (i% - 1) * 4 + 1, 4)) Wend Next Romanize$ = romanNum$ End Function Function Numeralize% (Roman$) copy$ = Roman$ For i% = 2 To 12 Step 2 place% = InStr(copy$, _Trim$(Mid$(Symbol$, (i% - 1) * 2 + 1, 2))) If place% Then tot% = tot% + Val(Mid$(Value$, (i% - 1) * 4 + 1, 4)): Mid$(copy$, place%, 2) = " " Next For i% = 1 To 13 Step 2 place% = InStr(copy$, _Trim$(Mid$(Symbol$, (i% - 1) * 2 + 1, 2))) While place% tot% = tot% + Val(Mid$(Value$, (i% - 1) * 4 + 1, 4)) Mid$(copy$, place%, 1) = " " place% = InStr(copy$, _Trim$(Mid$(Symbol$, (i% - 1) * 2 + 1, 2))) Wend Next Numeralize% = tot% End Function
|
|
|
Post by carlos45 on Aug 18, 2024 0:21:14 GMT
Good evening, Bplus.
I am gradually migrating my codes to function blocks and SUB. When I see examples like yours, I become even more interested in migrating to functions. I didn't want to open a topic just for a function that I am having trouble calling. When I implement it as a SUB, I can call it easily, but I am having problems with the function version.
If you ask me if the SUB is working and why I want to transform the same block into a function, it is just to practice using functions more. Do you allow me to post here in your topic?
Carlos
|
|
|
Post by bplus on Aug 18, 2024 12:04:32 GMT
Hi carlos45, I think you should post your questions in Discussion Board. This is so other people curious about the same topic can try there instead of "Roman Numeral Converstions" which doesn't even sound close. Start a Discussion of "Starting Subs and Functions" or "Subs and Functions for Beginners" this is BIG important step for people learning QB64 and deserves it's own Topic in Discussions Board. OTOH I just happen to have 3 other versions of this code and it might be interesting demonstration to show how I evolved it to the one I posted at the beginning of this thread.
|
|
|
Post by bplus on Aug 18, 2024 12:29:10 GMT
This is how it started. SierraKen a great QB64 fan at another forum posted this code for converting numbers to Roman Numerals.
The numbers had to be limited to > 0 and < 4000 because we run out of Roman Symbols after M for 1000.
Here is his code:
'Thanks to ChatGPT for a little help figuring this out. I fixed the DIM numbers and removed the Function and made the code simpler. 'By SierraKen on Aug. 12, 2024 'I been wanting to make this since the 1990's! LOL Dim values(13) As Integer Dim symbols(13) As String _Title "Numbers To Roman Numerals Converter" Cls start: Input "Enter a number (1-3999): ", number If number < 1 Or number > 3999 Then Print "Number out of range. Please enter a number between 1 and 3999." Else values(1) = 1000: symbols(1) = "M" values(2) = 900: symbols(2) = "CM" values(3) = 500: symbols(3) = "D" values(4) = 400: symbols(4) = "CD" values(5) = 100: symbols(5) = "C" values(6) = 90: symbols(6) = "XC" values(7) = 50: symbols(7) = "L" values(8) = 40: symbols(8) = "XL" values(9) = 10: symbols(9) = "X" values(10) = 9: symbols(10) = "IX" values(11) = 5: symbols(11) = "V" values(12) = 4: symbols(12) = "IV" values(13) = 1: symbols(13) = "I" romanNum$ = "" num = number For i = 1 To 13 While num >= values(i) romanNum$ = romanNum$ + symbols(i) num = num - values(i) Wend Next i Print "Roman Numeral: "; romanNum$ End If Print: Print: Print GoTo start:
here are his comments on the code:
I just noticed in his comments in the code box that he took the AI code from a Function
This code looked easy to put back into a Function called Romanize$, a $ sign on the end because it will return a string. Function Romanize$(number as integer) ' insert here all the code of the main program except the Input line for a number and the prints and loop around. End Function
'Thanks to ChatGPT for a little help figuring this out. I fixed the DIM numbers and removed the Function and made the code simpler. 'By SierraKen on Aug. 12, 2024 'I been wanting to make this since the 1990's! LOL
' mod b+ 2024-08-12 _Title "Numbers To Roman Numerals Converter" For i = 1 To 3999 Print i, Romanize$(i) If i Mod 20 = 19 Then Print "Sleeping ...zzz, press any": Sleep: Cls Next
Function Romanize$ (number As Integer) Dim values(13) As Integer Dim symbols(13) As String
If number < 1 Or number > 3999 Then Romanize$ = "Number out of range. Please enter a number between 1 and 3999." Else values(1) = 1000: symbols(1) = "M" values(2) = 900: symbols(2) = "CM" values(3) = 500: symbols(3) = "D" values(4) = 400: symbols(4) = "CD" values(5) = 100: symbols(5) = "C" values(6) = 90: symbols(6) = "XC" values(7) = 50: symbols(7) = "L" values(8) = 40: symbols(8) = "XL" values(9) = 10: symbols(9) = "X" values(10) = 9: symbols(10) = "IX" values(11) = 5: symbols(11) = "V" values(12) = 4: symbols(12) = "IV" values(13) = 1: symbols(13) = "I" romanNum$ = "" num = number For i = 1 To 13 While num >= values(i) romanNum$ = romanNum$ + symbols(i) num = num - values(i) Wend Next i Romanize$ = romanNum$ End If End Function
It is VERY IMPORTANT TO NOTE that because number would be changed by the function we made a copy: num = number before doing the changes, so we changed num NOT the number variable.
REMEMBER in QB64 ALL ARGUMENTS are passed BY REFERENCE!!! Which means if you change it, it will be changed in the main program as well! So aways make a copy of a variable you are going to change in the Sub or Function unless you intentionally want to have the value changed when you return back from sub or function to the code that called the sub or function.
|
|
|
Post by bplus on Aug 18, 2024 13:08:20 GMT
Then I thought it would be right and proper to do a function that takes a Roman Numeral and convert it back to a number.
Here it is step by step
'Thanks to ChatGPT for a little help figuring this out. I fixed the DIM numbers and removed the Function and made the code simpler. 'By SierraKen on Aug. 12, 2024 'I been wanting to make this since the 1990's! LOL
' b+ mod 2 2024-08-12 $Console:Only _Title "Numbers To Roman Numerals Converter" B$ = String$(15, " ") For i = 1 To 3999 r$ = Romanize$(i) C$ = B$ Mid$(C$, 1, Len(r$)) = r$ Print i, C$, Numeralize%(r$) Next
Function Romanize$ (number As Integer) Dim values(13) As Integer Dim symbols(13) As String
If number < 1 Or number > 3999 Then Romanize$ = "Number out of range. Please enter a number between 1 and 3999." Else values(1) = 1000: symbols(1) = "M" values(2) = 900: symbols(2) = "CM" values(3) = 500: symbols(3) = "D" values(4) = 400: symbols(4) = "CD" values(5) = 100: symbols(5) = "C" values(6) = 90: symbols(6) = "XC" values(7) = 50: symbols(7) = "L" values(8) = 40: symbols(8) = "XL" values(9) = 10: symbols(9) = "X" values(10) = 9: symbols(10) = "IX" values(11) = 5: symbols(11) = "V" values(12) = 4: symbols(12) = "IV" values(13) = 1: symbols(13) = "I" romanNum$ = "" num = number For i = 1 To 13 While num >= values(i) romanNum$ = romanNum$ + symbols(i) num = num - values(i) Wend Next i Romanize$ = romanNum$ End If End Function
Function Numeralize% (Roman$) Dim tot As Integer Dim copy As String copy = Roman$ place = InStr(copy, "CM") If place Then tot = tot + 900: Mid$(copy, place, 2) = " " place = InStr(copy, "CD") If place Then tot = tot + 400: Mid$(copy, place, 2) = " " place = InStr(copy, "XC") If place Then tot = tot + 90: Mid$(copy, place, 2) = " " place = InStr(copy, "XL") If place Then tot = tot + 40: Mid$(copy, place, 2) = " " place = InStr(copy, "IX") If place Then tot = tot + 9: Mid$(copy, place, 2) = " " place = InStr(copy, "IV") If place Then tot = tot + 4: Mid$(copy, place, 2) = " " place = InStr(copy, "M") While place tot = tot + 1000 Mid$(copy, place, 1) = " " place = InStr(copy, "M") Wend place = InStr(copy, "D") While place tot = tot + 500 Mid$(copy, place, 1) = " " place = InStr(copy, "D") Wend place = InStr(copy, "C") While place tot = tot + 100 Mid$(copy, place, 1) = " " place = InStr(copy, "C") Wend place = InStr(copy, "L") While place tot = tot + 50 Mid$(copy, place, 1) = " " place = InStr(copy, "L") Wend place = InStr(copy, "X") While place tot = tot + 10 Mid$(copy, place, 1) = " " place = InStr(copy, "X") Wend place = InStr(copy, "V") While place tot = tot + 5 Mid$(copy, place, 1) = " " place = InStr(copy, "V") Wend place = InStr(copy, "I") While place tot = tot + 1 Mid$(copy, place, 1) = " " place = InStr(copy, "I") Wend Numeralize% = tot End Function
I put it in Console so you could scroll all the way up and down through all to numbers and their conversions and their convertions back.
|
|
|
Post by bplus on Aug 18, 2024 13:34:55 GMT
Here is an optimization of the above code. I Shared the Values() and Symbols() so they can be seen by the 2 Functions that use them and I simplified the repititious stuff in the Numeralize$ function by plugging the array values in indexed by i = 1 to 13.
First you have to notice that all the 2 digit symbols were even numbered and they only appear once (if at all) in any Roman Numeral. They had to be taken out first before we start counting the number of single letter symbols otherwise I's in 4, IV, or 9, IX, would be added again and mess up the accounting.
_Title "Roman Numerals Converter mod 3 2024-08-13" ' third mod to SierraKen's great start: ' "Thanks to ChatGPT for a little help figuring this out. ' I fixed the DIM numbers and removed the Function and made the code simpler. ' By SierraKen on Aug. 12, 2024"
Dim Shared Values(1 To 13) As Integer, Symbols(1 To 13) As String Values(1) = 1000: Symbols(1) = "M" Values(2) = 900: Symbols(2) = "CM" Values(3) = 500: Symbols(3) = "D" Values(4) = 400: Symbols(4) = "CD" Values(5) = 100: Symbols(5) = "C" Values(6) = 90: Symbols(6) = "XC" Values(7) = 50: Symbols(7) = "L" Values(8) = 40: Symbols(8) = "XL" Values(9) = 10: Symbols(9) = "X" Values(10) = 9: Symbols(10) = "IX" Values(11) = 5: Symbols(11) = "V" Values(12) = 4: Symbols(12) = "IV" Values(13) = 1: Symbols(13) = "I"
$Console:Only
B$ = String$(15, " ") For i = 1 To 3999 r$ = Romanize$(i): C$ = B$: n% = Numeralize%(r$) Mid$(C$, 1, Len(r$)) = r$ Print i, C$; n% If i <> n% Then Beep: Sleep ' keep us honest :) Next
Function Romanize$ (number As Integer) If number < 1 Or number > 3999 Then Romanize$ = "Number out of range. Please enter a number between 1 and 3999." Else romanNum$ = "" num = number For i = 1 To 13 While num >= Values(i) romanNum$ = romanNum$ + Symbols(i) num = num - Values(i) Wend Next i Romanize$ = romanNum$ End If End Function
Function Numeralize% (Roman$) Dim As Integer tot, i Dim copy As String copy = Roman$ For i = 2 To 12 Step 2 place = InStr(copy, Symbols(i)) If place Then tot = tot + Values(i): Mid$(copy, place, 2) = " " Next For i = 1 To 13 Step 2 place = InStr(copy, Symbols(i)) While place tot = tot + Values(i) Mid$(copy, place, 1) = " " place = InStr(copy, Symbols(i)) Wend Next Numeralize% = tot End Function
The 4th mod is the one I posted at the start of this thread. I cut the 13 lines that defined the values of the 2 shared arrays and replaced them with two shared strings using Mid$ and index to find where in string the value was and if it was a number I used Val() to convert it to a number.
|
|