Jump to content

Lunar arithmetic

From Rosetta Code
Lunar arithmetic is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
This page uses content from Wikipedia. The original article was at Lunar arithmetic. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)

Lunar arithmetic is a version of arithmetic in which the addition and multiplication on digits are defined as the max and min operations. Thus, in lunar arithmetic,

and

The lunar arithmetic operations on nonnegative multidigit numbers are performed as in usual arithmetic as illustrated in the following examples. The world of lunar arithmetic is restricted to the set of nonnegative integers.

 976 +
 348
 ----
 978 (adding digits column-wise)
    976 ×
    348
   ----
   876 (multiplying the digits of 976 by 8)
  444  (multiplying the digits of 976 by 4)
 333   (multiplying the digits of 976 by 3)
 ------
 34876 (adding digits column-wise)

A few important properties of lunar arithmetic

  1. The lunar addition and multiplication operations satisfy the Commutative and Associative property laws.
  2. The lunar multiplication distributes over the lunar addition.
  3. The digit 0 is the additive identity under lunar addition.
  4. The digit 9 is the multiplicative identity under lunar multiplication.

Note that lunar arithmetic can be done in any base. This task is restricted to base 10 only.


Task

Implement lunar addition and lunar multiplication routines. Extra kudos for implementing them as operators.

Use those routines (operators) to perform the following:

  • Lunar addition and lunar multiplication of the number groups: (976, 348), (23, 321), (232, 35), (123, 32192, 415, 8)
  • Using lunar arithmetic, find the first twenty distinct even numbers. and . The even numbers are numbers of the form .
  • Using lunar arithmetic, find the first twenty square numbers.
  • Using lunar arithmetic, find the first twenty factorial numbers.


Stretch

The lunar squares sequence is not monotonic. Squared values are not strictly increasing as the numbers grow larger.

  • Find the first number whose lunar square is smaller than the previous.


See also
OEIS A087019 - Lunar squares
OEIS A189788 - Base-10 lunar factorials
Tropical algebra overloading


ALGOL 68

Assumes INT is large enough to hold the 20th lunar factorial - this is true for ALGOL 68 Genie version 3, but not version 2.

Algol 68 allows the definition of new operators, either symbolic or with alphabetic names. For symbolic operators 1 and 2 character names, possibly followed by := or =: are allowed. However, monadic operator names cannot start with <. =, >, / or *, so although <* is OK as a dyadic operator, it isn't allowed as a monadic operator - which is why the monadic lunar multiplication operator defined here (to calculate the lunar product of the elements of an array) is called CX.

Algol 68n implementations tend not to do Unicode, so the lunar operators can't have a crescent in their names so-+> and <* are used here - that's not a relational operator, it's a crescent moon... : )

BEGIN # Lunar arithmetic                                                     #

    INT max lunar digits = ENTIER log( max int ); # maximum number of digits #
                                                  # a lunar number can have  #
                                                  # if stored in an INT      #
    [ 1 : max lunar digits + 1 ]INT lunar digits;

    PRIO +> = 6, <* = 7;                        # same priorities as + and * #
    OP   +> = ( INT a, b )INT:                   # lunar addition of a and b #
         IF a < 0 OR b < 0
         THEN print( ( "Lunar numbers must be non-negative", newline ) );
              stop
         ELIF a = b
         THEN a
         ELSE INT v1 := a, v2 := b;
              INT d pos := 0;
              WHILE v1 > 0 OR v2 > 0 DO
                  INT d1 = v1 MOD 10, d2 = v2 MOD 10;
                  lunar digits[ d pos +:= 1 ] := IF d1 > d2 THEN d1 ELSE d2 FI;
                  v1 OVERAB 10;
                  v2 OVERAB 10
              OD;
              INT result := lunar digits[ d pos ];
              WHILE ( d pos -:= 1 ) > 0 DO
                  result *:= 10 +:= lunar digits[ d pos ]
              OD;
              result
         FI # +> # ;
    PRIO +>:= = 1;              # lunar add-and-assign, same priority as +:= #
    OP   +>:= = ( REF INT a, INT b )REF INT: a := a +> b;

    OP   <* = ( INT a, b )INT:             # lunar multiplication of a and b #
         IF a < 0 OR b < 0
         THEN printf( ( "Lunar numbers must be non-negative", newline ) );
              stop
         ELIF a = 0 OR b = 0
         THEN 0
         ELSE INT v2 := b, multiplier := 1;
              INT result := 0;
              WHILE v2 > 0 DO
                  INT d2     = v2 MOD 10;
                  INT d pos := 0;
                  INT v1    := a;
                  WHILE v1 > 0 DO
                      INT d1 = v1 MOD 10;
                      lunar digits[ d pos +:= 1 ] := IF d1 < d2 THEN d1 ELSE d2 FI;
                      v1 OVERAB 10
                  OD;
                  INT p1 := lunar digits[ d pos ];
                  WHILE ( d pos -:= 1 ) > 0 DO
                      p1 *:= 10 +:= lunar digits[ d pos ]
                  OD;
                  result    +>:= p1 * multiplier;
                  multiplier *:= 10;
                  v2 OVERAB 10
              OD;
              result
         FI # <* # ;
    PRIO <*:= = 1;         # lunar multiply-and-assign, same priority as *:= #
    OP   <*:= = ( REF INT a, INT b )REF INT: a := a <* b;

    OP   +> = ( []INT a )INT:          # lunar addition of the elements of a #
         BEGIN
            INT result := IF UPB a < LWB a THEN 0 ELSE a[ LWB a ] FI;
            FOR a pos FROM LWB a + 1 TO UPB a DO
                result +>:= a[ a pos ]
            OD;
            result
         END # +> # ;
    OP   CX = ( []INT a )INT:    # lunar multiplication of the elements of a #
         BEGIN         # unfortunately, <* isn't a valid unary operator name #
            INT result := IF UPB a < LWB a THEN 0 ELSE a[ LWB a ] FI;
            FOR a pos FROM LWB a + 1 TO UPB a DO
                result <*:= a[ a pos ]
            OD;
            result
         END # CX # ;

    BEGIN # task                                                             #
        [][]INT tests = ( ( 976, 348 ), ( 23, 321 ), ( 232, 35 ), ( 123, 32192, 415, 8 ) );
        PROC show test = ( []INT v, STRING op name, INT result )VOID:
             IF UPB v >= LWB v THEN
                print( ( whole( v[ LWB v ], -8 ) ) );
                FOR v pos FROM LWB v + 1 TO UPB v DO
                    print( ( " ", op name, " ", whole( v[ v pos ], 0 ) ) )
                OD;
                print( ( " = ", whole( result, 0 ), newline ) )
             FI # show test # ;

        print( ( "Lunar addition (+>):", newline ) );
        FOR t pos FROM 1 LWB tests TO 1 UPB tests DO
            show test( tests[ t pos ], "+>", +> tests[ t pos ] )
        OD;
        print( ( "Lunar multiplication (<*):", newline ) );
        FOR t pos FROM 1 LWB tests TO 1 UPB tests DO
            show test( tests[ t pos ], "<*", CX tests[ t pos ] )
        OD;
        BEGIN
            print( ( "The first 20 distinct even lunar numbers:", newline, "      " ) );
            [ 0 : 1000 ]BOOL even;              # assume they are all < 1001 #
            FOR n FROM LWB even TO UPB even DO even[ n ] := FALSE OD;
            FOR n FROM LWB even TO UPB even DO
                IF INT n2 = n <* 2; n2 <= UPB even THEN even[ n <* 2 ] := TRUE FI
            OD;
            INT found := 0;
            FOR n FROM LWB even WHILE found < 20 DO
                IF even[ n ] THEN print( ( " ", whole( n, 0 ) ) ); found +:= 1 FI
            OD;
            print( ( newline ) )
        END;
        print( ( "The first 20 lunar squares:", newline, "      " ) );
        FOR n FROM 0 TO 19 DO print( ( " ", whole( n <* n, 0 ) ) ) OD;
        print( ( newline ) );
        BEGIN
            INT f max = IF max lunar digits >= 18 THEN 20 ELIF max lunar digits >= 9 THEN 18 ELSE 9 FI;
            print( ( "The first ", whole( f max, 0 ), " lunar factorials:", newline, "      " ) );
            INT lf := 1;
            FOR n TO f max DO print( ( " ", whole( lf <*:= n, 0 ) ) ) OD;
            print( ( newline ) )
        END;
        BEGIN
            print( ( "First lunar square smaller than the previous: " ) );
            INT prev square := 0;
            INT this square := 1;
            INT first n     := 0;
            FOR n FROM 2 WHILE first n = 0 DO
                prev square := this square;
                IF   this square := n <* n;
                     this square < prev square
                THEN first n := n
                FI
            OD;
            print( ( whole( first n, 0 ), " squared = ", whole( this square, 0 ) ) );
            print( ( ", previous = ", whole( prev square, 0 ), newline ) )
        END        
    END
END
Output:
Lunar addition (+>):
     976 +> 348 = 978
      23 +> 321 = 323
     232 +> 35 = 235
     123 +> 32192 +> 415 +> 8 = 32498
Lunar multiplication (<*):
     976 <* 348 = 34876
      23 <* 321 = 2321
     232 <* 35 = 2332
     123 <* 32192 <* 415 <* 8 = 123233232
The first 20 distinct even lunar numbers:
       0 1 2 10 11 12 20 21 22 100 101 102 110 111 112 120 121 122 200 201
The first 20 lunar squares:
       0 1 2 3 4 5 6 7 8 9 100 111 112 113 114 115 116 117 118 119
The first 18 lunar factorials:
       1 1 1 1 1 1 1 1 1 10 110 1110 11110 111110 1111110 11111110 111111110 1111111110
First lunar square smaller than the previous: 1020 squared = 1010200, previous = 1011119

BASIC

FreeBASIC

Translation of: Raku
Function LunarAdd(a As String, b As String) As String
    Dim result As String
    Dim maxLen As Integer = Iif(Len(a) > Len(b), Len(a), Len(b))
    
    a = String(maxLen - Len(a), "0") & a
    b = String(maxLen - Len(b), "0") & b
    
    For i As Integer = 1 To maxLen
        Dim digit As Integer = Iif(Val(Mid(a, i, 1)) > Val(Mid(b, i, 1)), Val(Mid(a, i, 1)), Val(Mid(b, i, 1)))
        result &= Str(digit)
    Next
    
    Return Ltrim(result)
End Function

Function LunarMultiply(a As String, b As String = "9") As String
    If a = "0" Or b = "0" Then Return "0"
    
    Dim result As String = "0"
    For i As Integer = Len(b) To 1 Step -1
        Dim tmp As String = ""
        Dim bDigit As Integer = Val(Mid(b, i, 1))
        
        For j As Integer = 1 To Len(a)
            Dim aDigit As Integer = Val(Mid(a, j, 1))
            tmp &= Str(Iif(aDigit < bDigit, aDigit, bDigit))
        Next
        
        tmp &= String(Len(b) - i, "0")
        result = LunarAdd(result, Ltrim(tmp))
    Next
    
    Return result
End Function

Function isUnique(value As String, arr() As String, cnt As Integer) As Boolean
    For i As Integer = 0 To cnt - 1
        If arr(i) = value Then Return False
    Next
    Return True
End Function

Sub main()
    Print "     Lunar add: 976 + 348 = "; LunarAdd("976", "348")
    Print "Lunar multiply: 976 x 348 = "; LunarMultiply("976", "348")
    Print
    
    Print "     Lunar add: 23 + 321 = "; LunarAdd("23", "321")
    Print "Lunar multiply: 23 x 321 = "; LunarMultiply("23", "321")
    Print
    
    Print "     Lunar add: 232 + 35 = "; LunarAdd("232", "35")
    Print "Lunar multiply: 232 x 35 = "; LunarMultiply("232", "35")
    Print
    
    Print "     Lunar add: 123 + 32192 + 415 + 8 = "; LunarAdd(LunarAdd(LunarAdd("123", "32192"), "415"), "8")
    Print "Lunar multiply: 123 x 32192 x 415 x 8 = "; LunarMultiply(LunarMultiply(LunarMultiply("123", "32192"), "415"), "8")
    Print
    
    Print "First 20 distinct lunar even numbers:"
    Dim evenNums(1000) As String
    Dim cnt As Integer = 0
    Dim n As Integer = 0
    Do While cnt < 20
        Dim result As String = LunarMultiply(Str(n), "2")
        If isUnique(result, evenNums(), cnt) Then
            evenNums(cnt) = result
            Print result; " ";
            cnt += 1
        End If
        n += 1
    Loop
    
    Print !"\n\nFirst 20 lunar square numbers:"
    For i As Integer = 0 To 19
        Print LunarMultiply(Str(i), Str(i)); " ";
    Next
    
    Print !"\n\nFirst 20 lunar factorial numbers:"
    Dim factorial As String = "1"
    Print "1";
    For i As Integer = 1 To 19
        factorial = LunarMultiply(factorial, Str(i + 1))
        Print " "; factorial;
    Next
    
    Dim prevSquare As String = ""
    Dim currSquare As String
    
    For i As LongInt = 1 To 1200
        currSquare = lunarMultiply(Str(i), Str(i))
        
        If prevSquare <> "" AndAlso Val(currSquare) < Val(prevSquare) Then
            Print !"\n\nFirst number whose lunar square is smaller than the previous:"; i
            Exit For
        End If
        
        prevSquare = currSquare
    Next
End Sub

main()

Sleep
Output:
     Lunar add: 976 + 348 = 978
Lunar multiply: 976 x 348 = 34876

     Lunar add: 23 + 321 = 323
Lunar multiply: 23 x 321 = 2321

     Lunar add: 232 + 35 = 235
Lunar multiply: 232 x 35 = 2332

     Lunar add: 123 + 32192 + 415 + 8 = 32498
Lunar multiply: 123 x 32192 x 415 x 8 = 123233232

First 20 distinct even lunar numbers:
0 1 2 10 11 12 20 21 22 100 101 102 110 111 112 120 121 122 200 201

First 20 square lunar numbers:
0 1 2 3 4 5 6 7 8 9 100 111 112 113 114 115 116 117 118 119

First 20 factorial lunar numbers:
1 1 1 1 1 1 1 1 1 10 110 1110 11110 111110 1111110 11111110 111111110 1111111110 11111111110 111111111100 

First number whose lunar square is smaller than the previous: 1020

Gambas

Translation of: FreeBASIC
Private evenNums As New String[]

Public Function LunarAdd(a As String, b As String) As String 
  
  Dim result As String 
  Dim maxLen As Integer = IIf(Len(a) > Len(b), Len(a), Len(b)) 
  Dim i As Integer
  
  a = String$(maxLen - Len(a), "0") & a 
  b = String$(maxLen - Len(b), "0") & b 
  
  For i = 1 To maxLen 
    result &= IIf(Val(Mid$(a, i, 1)) > Val(Mid$(b, i, 1)), Mid$(a, i, 1), Mid$(b, i, 1)) 
  Next 
  
  Return LTrim(result) 
  
End

Public Function LunarMultiply(a As String, b As String) As String 
  
  If a = "0" Or b = "0" Then Return "0" 
  
  Dim i As Integer, j As Integer
  Dim result As String = "0" 
  For i = Len(b) To 1 Step -1 
    Dim tmp As String = "" 
    Dim bDigit As Integer = Val(Mid$(b, i, 1)) 
    
    For j = 1 To Len(a) 
      Dim aDigit As Integer = Val(Mid$(a, j, 1)) 
      tmp &= Min(aDigit, bDigit) 
    Next 
    
    tmp &= String$(Len(b) - i, "0") 
    result = LunarAdd(result, tmp) 
  Next 
  
  Return result 
  
End 

Public Function isUnique(value As String, arr As String[], cnt As Integer) As Boolean 
  
  For i As Integer = 0 To cnt - 1 
    If arr[i] = value Then Return False 
  Next 
  Return True 
  
End

Public Sub main() 
  
  Print "     Lunar add: 976 + 348 == "; LunarAdd("976", "348") 
  Print "Lunar multiply: 976 × 348 == "; LunarMultiply("976", "348")
  Print 
  
  Print "     Lunar add: 23 + 321 = "; LunarAdd("23", "321") 
  Print "Lunar multiply: 23 x 321 = "; LunarMultiply("23", "321") 
  Print 
  
  Print "     Lunar add: 232 + 35 = "; LunarAdd("232", "35") 
  Print "Lunar multiply: 232 x 35 = "; LunarMultiply("232", "35") 
  Print 
  
  Print "     Lunar add: 123 + 32192 + 415 + 8 = "; LunarAdd(LunarAdd(LunarAdd("123", "32192"), "415"), "8") 
  Print "Lunar multiply: 123 x 32192 x 415 x 8 = "; LunarMultiply(LunarMultiply(LunarMultiply("123", "32192"), "415"), "8") 
  Print 
  
  Print "First 20 distinct lunar even numbers:" 
  '    Dim evenNums(1000) As String 
  Dim cnt As Integer = 0 
  Dim n As Integer = 0 
  Do While cnt < 20 
    Dim result As String = LunarMultiply(Str(n), "2") 
    If isUnique(result, evenNums, cnt) Then 
      evenNums.Add(result)
      Print result; " "; 
      cnt += 1 
    End If 
    n += 1 
  Loop 
  
  Print "\n\nFirst 20 lunar square numbers:" 
  For i As Integer = 0 To 19 
    Print LunarMultiply(Str(i), Str(i)); " "; 
  Next 
  
  Print "\n\nFirst 20 lunar factorial numbers:" 
  Dim factorial As String = "1" 
  Print "1"; 
  For i As Integer = 1 To 19 
    factorial = LunarMultiply(factorial, Str(i + 1)) 
    Print " "; factorial; 
  Next 
  
  n = 1
  Dim prevSquare, currSquare As String 
  prevSquare = LunarMultiply(Str(n), Str(n)) 
  
  Do 
    currSquare = LunarMultiply(Str(n + 1), Str(n + 1)) 
    If prevSquare <> "" And Val(currSquare) < Val(prevSquare) Then
      Print "\n\nFirst number whose lunar square is smaller than the previous: "; n + 1 
      Break 
    Endif
    prevSquare = currSquare 
    n += 1 
  Loop
  
End
Output:
Same as FreeBASIC entry.

PureBasic

Translation of: FreeBASIC
Procedure Max(a, b)
  If a > b
    ProcedureReturn a
  EndIf
  ProcedureReturn b
EndProcedure

Procedure Min(a, b)
  If a < b
    ProcedureReturn a
  EndIf
  ProcedureReturn b
EndProcedure

Procedure.s LunarAdd(a.s, b.s)
  maxLen = Max(Len(a), Len(b))
  a = RSet(a, maxLen, "0")
  b = RSet(b, maxLen, "0")
  
  result.s = ""
  For i = 1 To maxLen
    digit1 = Val(Mid(a, i, 1))
    digit2 = Val(Mid(b, i, 1))
    result + Str(Max(digit1, digit2))
  Next
  
  ProcedureReturn Trim(result)
EndProcedure

Procedure.s LunarMultiply(a.s, b.s)
  If a = "0" Or b = "0"
    ProcedureReturn "0"
  EndIf
  
  result.s = "0"
  For i = Len(b) To 1 Step -1
    tmp.s = ""
    bDigit = Val(Mid(b, i, 1))
    
    For j = 1 To Len(a)
      aDigit = Val(Mid(a, j, 1))
      tmp + Str(Min(aDigit, bDigit))
    Next
    
    tmp + RSet("", Len(b) - i, "0")
    result = LunarAdd(result, tmp)
  Next
  
  ProcedureReturn result
EndProcedure

Procedure isUnique(value.s, Array arr.s(1), cnt)
  For i = 0 To cnt - 1
    If arr(i) = value
      ProcedureReturn #False
    EndIf
  Next
  ProcedureReturn #True
EndProcedure

OpenConsole()
Define result.s
; First test set
PrintN("     Lunar add: 976 + 348 = " + LunarAdd("976", "348"))
PrintN("Lunar multiply: 976 × 348 = " + LunarMultiply("976", "348") + #CRLF$)

; Second test set
PrintN("     Lunar add: 23 + 321 = " + LunarAdd("23", "321"))
PrintN("Lunar multiply: 23 × 321 = " + LunarMultiply("23", "321") + #CRLF$)

; Third test set
PrintN("     Lunar add: 232 + 35 = " + LunarAdd("232", "35"))
PrintN("Lunar multiply: 232 × 35 = " + LunarMultiply("232", "35") + #CRLF$)

; Fourth test set
result = LunarAdd(LunarAdd(LunarAdd("123", "32192"), "415"), "8")
PrintN("     Lunar add: 123 + 32192 + 415 + 8 = " + result)
result = LunarMultiply(LunarMultiply(LunarMultiply("123", "32192"), "415"), "8")
PrintN("Lunar multiply: 123 × 32192 × 415 × 8 = " + result + #CRLF$)

; Lunar even numbers
PrintN("First 20 distinct lunar even numbers:")
Dim evenNums.s(1000)
cnt = 0
n = 0
While cnt < 20
  result.s = LunarMultiply(Str(n), "2")
  If isUnique(result, evenNums(), cnt)
    evenNums(cnt) = result
    Print(result + " ")
    cnt + 1
  EndIf
  n + 1
Wend

; Lunar squares
PrintN(#CRLF$ + #CRLF$ + "First 20 lunar square numbers:")
For i = 0 To 19
  Print(LunarMultiply(Str(i), Str(i)) + " ")
Next

; Lunar factorials
PrintN(#CRLF$ + #CRLF$ + "First 20 lunar factorial numbers:")
factorial.s = "1"
Print("1")
For i = 1 To 19
  factorial = LunarMultiply(factorial, Str(i + 1))
  Print(" " + factorial)
Next

n = 1
prevSquare.s = LunarMultiply(Str(n), Str(n))

Repeat
  ;prevSquare.s = LunarMultiply(Str(n), Str(n))
  currSquare.s = LunarMultiply(Str(n + 1), Str(n + 1))
  If prevSquare <> "" And Val(currSquare) < Val(prevSquare)
    PrintN(#CRLF$ + #CRLF$ + "First number whose lunar square is smaller than the previous: " + Str(n + 1))
    Break
  EndIf
  prevSquare = currSquare
  n + 1
ForEver

PrintN(#CRLF$ + "Press ENTER to exit"): Input()
Output:
Similar to FreeBASIC entry.

QBasic

Translation of: FreeBASIC
Works with: QBasic version 1.1
Works with: QuickBasic version 4.5
Works with: QB64
DECLARE FUNCTION PadLeft$ (s AS STRING, length AS INTEGER)
DECLARE FUNCTION LunarAdd$ (a AS STRING, b AS STRING)
DECLARE FUNCTION LunarMultiply$ (a AS STRING, b AS STRING)
DECLARE FUNCTION isUnique% (value AS STRING, arr$(), cnt AS INTEGER)

PRINT "     Lunar add: 976 + 348 = "; LunarAdd$("976", "348")
PRINT "Lunar multiply: 976 x 348 = "; LunarMultiply$("976", "348")
PRINT

PRINT "     Lunar add: 23 + 321 = "; LunarAdd$("23", "321")
PRINT "Lunar multiply: 23 x 321 = "; LunarMultiply$("23", "321")
PRINT

PRINT "     Lunar add: 232 + 35 = "; LunarAdd$("232", "35")
PRINT "Lunar multiply: 232 x 35 = "; LunarMultiply$("232", "35")
PRINT

PRINT "     Lunar add: 123 + 32192 + 415 + 8 = "; LunarAdd$(LunarAdd$(LunarAdd$("123", "32192"), "415"), "8")
PRINT "Lunar multiply: 123 x 32192 x 415 x 8 = "; LunarMultiply$(LunarMultiply$(LunarMultiply$("123", "32192"), "415"), "8")
PRINT

PRINT "First 20 distinct lunar even numbers:"
DIM evenNums$(1000)
DIM cnt AS INTEGER, n AS INTEGER, i AS INTEGER
DO WHILE cnt < 20
    DIM result AS STRING
    result = LunarMultiply$(STR$(n), "2")
    IF isUnique%(result, evenNums$(), cnt) THEN
        evenNums$(cnt) = result
        PRINT result; " ";
        cnt = cnt + 1
    END IF
    n = n + 1
LOOP

PRINT
PRINT
PRINT "First 20 lunar square numbers:"
FOR i = 0 TO 19
    PRINT LunarMultiply$(STR$(i), STR$(i)); " ";
NEXT i

PRINT
PRINT
PRINT "First 20 lunar factorial numbers:"
DIM factorial AS STRING
factorial = "1"
PRINT factorial;

FOR i = 2 TO 20
    factorial = LunarMultiply$(factorial, STR$(i))
    PRINT " "; factorial;
NEXT i

PRINT
PRINT

DIM prevSquare AS STRING, currSquare AS STRING
DIM j AS LONG
j = 1

DO
    currSquare = LunarMultiply$(STR$(j), STR$(j))

    IF prevSquare <> "" AND VAL(currSquare) < VAL(prevSquare) THEN
        PRINT "First number whose lunar square is smaller than the previous:"; j
        EXIT DO
    END IF

    prevSquare = currSquare
    j = j + 1
LOOP
END


FUNCTION isUnique% (value AS STRING, arr$(), cnt AS INTEGER)
    DIM i AS INTEGER
    FOR i = 0 TO cnt - 1
        IF arr$(i) = value THEN
            isUnique% = 0
            EXIT FUNCTION
        END IF
    NEXT i
    isUnique% = -1
END FUNCTION

FUNCTION LunarAdd$ (a AS STRING, b AS STRING)
    DIM result AS STRING
    DIM maxLen AS INTEGER, i AS INTEGER
    DIM digitA AS INTEGER, digitB AS INTEGER, digit AS INTEGER
    IF LEN(a) > LEN(b) THEN maxLen = LEN(a) ELSE maxLen = LEN(b)

    a = PadLeft$(a, maxLen)
    b = PadLeft$(b, maxLen)

    FOR i = 1 TO maxLen
        digitA = VAL(MID$(a, i, 1))
        digitB = VAL(MID$(b, i, 1))
        IF digitA > digitB THEN digit = digitA ELSE digit = digitB
        result = result + CHR$(ASC("0") + digit)
    NEXT i

    WHILE LEFT$(result, 1) = "0" AND LEN(result) > 1
        result = RIGHT$(result, LEN(result) - 1)
    WEND

    LunarAdd$ = result
END FUNCTION

FUNCTION LunarMultiply$ (a AS STRING, b AS STRING)
    IF a = "0" OR b = "0" THEN
        LunarMultiply$ = "0"
        EXIT FUNCTION
    END IF

    DIM result AS STRING, tmp AS STRING
    result = "0"
    DIM i AS INTEGER, j AS INTEGER
    DIM bDigit AS INTEGER, aDigit AS INTEGER
    FOR i = LEN(b) TO 1 STEP -1
        tmp = ""
        bDigit = VAL(MID$(b, i, 1))

        FOR j = 1 TO LEN(a)
            aDigit = VAL(MID$(a, j, 1))
            IF aDigit < bDigit THEN
                tmp = tmp + CHR$(ASC("0") + aDigit)
            ELSE
                tmp = tmp + CHR$(ASC("0") + bDigit)
            END IF
        NEXT j

        tmp = tmp + STRING$(LEN(b) - i, "0")
        result = LunarAdd$(result, tmp)
    NEXT i

    WHILE LEFT$(result, 1) = "0" AND LEN(result) > 1
        result = RIGHT$(result, LEN(result) - 1)
    WEND

    LunarMultiply$ = result
END FUNCTION

FUNCTION PadLeft$ (s AS STRING, length AS INTEGER)
    IF LEN(s) >= length THEN
        PadLeft$ = s
    ELSE
        PadLeft$ = STRING$(length - LEN(s), "0") + s
    END IF
END FUNCTION
Output:
Same as FreeBASIC entry.

QB64

The QBasic solution works without any changes.

EasyLang

func luadd a b .
   e = 1
   while a > 0 or b > 0
      d = higher (a mod 10) (b mod 10)
      a = a div 10
      b = b div 10
      r += d * e
      e *= 10
   .
   return r
.
func lumul a0 b .
   e0 = 1
   while b > 0
      e = e0
      r = 0
      a = a0
      while a > 0
         d = lower (a mod 10) (b mod 10)
         a = a div 10
         r += d * e
         e *= 10
      .
      s = luadd s r
      b = b div 10
      e0 *= 10
   .
   return s
.
tests[][] = [ [ 976 348 ] [ 23 321 ] [ 232 35 ] [ 123 32192 415 8 ] ]
for i to len tests[][]
   s = 0
   p = 9
   for h in tests[i][]
      s = luadd s h
      p = lumul p h
   .
   print "🌙+ " & tests[i][] & " -> " & s
   print "🌙* " & tests[i][] & " -> " & p
   print ""
.
print "First 20 distinct 🌙 even numbers:"
n = 1
while len nums[] < 20
   r = lumul n 2
   h = -1
   for h in nums[]
      if h = r : break 1
   .
   if h = -1 : nums[] &= r
   n += 1
.
for h in nums[] : write h & " "
print ""
print ""
print "First 20 🌙 square numbers:"
for i to 20
   write lumul i i & " "
.
print ""
print ""
print "First 20 🌙 factorial numbers:"
fac = 1
for i to 20
   fac = lumul fac i
   write fac & " "
.
print ""
print ""
h = 0
i = 1
repeat
   h = lumul i i
   until h < hp
   i += 1
   hp = h
.
print "First number whose 🌙 square is smaller than the previous: " & i
Output:
🌙+ [ 976 348 ] -> 978
🌙* [ 976 348 ] -> 34876

🌙+ [ 23 321 ] -> 323
🌙* [ 23 321 ] -> 2321

🌙+ [ 232 35 ] -> 235
🌙* [ 232 35 ] -> 2332

🌙+ [ 123 32192 415 8 ] -> 32498
🌙* [ 123 32192 415 8 ] -> 123233232

First 20 distinct 🌙 even numbers:
1 2 10 11 12 20 21 22 100 101 102 110 111 112 120 121 122 200 201 202 

First 20 🌙 square numbers:
1 2 3 4 5 6 7 8 9 100 111 112 113 114 115 116 117 118 119 200 

First 20 🌙 factorial numbers:
1 1 1 1 1 1 1 1 1 10 110 1110 11110 111110 1111110 11111110 111111110 1111111110 11111111110 111111111100 

First number whose 🌙 square is smaller than the previous: 1020

Python

Works with: Python version 3.x
Translation of: Raku
#!/usr/bin/python3

def lunar_add(a, b='0'):
    a, b = str(a), str(b)
    max_len = max(len(a), len(b))
    a = '0' * (max_len - len(a)) + a
    b = '0' * (max_len - len(b)) + b
    return ''.join(str(max(int(x), int(y))) for x, y in zip(a, b))

def lunar_multiply(a, b='9'):
    if a == '0' or b == '0':
        return '0'
    
    a, b = str(a), str(b)
    result = '0'
    for i, digit in enumerate(reversed(b)):
        temp = ''.join(str(min(int(x), int(digit))) for x in a)
        temp += '0' * i
        result = lunar_add(result, temp)
    return result

def lunar_factorial(n):
    if n <= 1:
        return '1'
    result = '1'
    for i in range(2, n + 1):
        result = lunar_multiply(result, str(i))
    return result

def main():
    # Test cases
    test_cases = [(976, 348), (23, 321), (232, 35), (123, 32192, 415, 8)]
    
    for case in test_cases:
        # Lunar addition
        add_expr = ' 🌙+ '.join(str(x) for x in case)
        add_result = reduce(lunar_add, map(str, case))
        print(f"     Lunar add: {add_expr} == {add_result}")
        
        # Lunar multiplication
        mult_expr = ' 🌙× '.join(str(x) for x in case)
        mult_result = reduce(lunar_multiply, map(str, case))
        print(f"Lunar multiply: {mult_expr} == {mult_result}")
        print()
    
    # First 20 distinct lunar even numbers
    even_nums = []
    n = 0
    while len(even_nums) < 20:
        result = lunar_multiply(str(n), '2')
        if result not in even_nums:
            even_nums.append(result)
        n += 1
    print("First 20 distinct lunar even numbers:")
    print(' '.join(even_nums))
    print()
    
    # First 20 lunar square numbers
    squares = [lunar_multiply(str(i), str(i)) for i in range(20)]
    print("First 20 lunar square numbers:")
    print(' '.join(squares))
    print()
    
    # First 20 lunar factorial numbers
    factorials = [lunar_factorial(i) for i in range(20)]
    print("First 20 lunar factorial numbers:")
    print(' '.join(factorials))
    print()

    # First number whose lunar square is smaller than previous
    n = 1019  # We can start closer to the known solution
    while True:
        curr_square = lunar_multiply(str(n), str(n))
        next_square = lunar_multiply(str(n + 1), str(n + 1))
        if curr_square > next_square:
            print(f"First number whose lunar square is smaller than the previous: {n + 1}")
            break
        n += 1

if __name__ == '__main__':
    from functools import reduce
    main()
Output:
     Lunar add: 976 🌙+ 348 == 978
Lunar multiply: 976 🌙× 348 == 34876

     Lunar add: 23 🌙+ 321 == 323
Lunar multiply: 23 🌙× 321 == 2321

     Lunar add: 232 🌙+ 35 == 235
Lunar multiply: 232 🌙× 35 == 2332

     Lunar add: 123 🌙+ 32192 🌙+ 415 🌙+ 8 == 32498
Lunar multiply: 123 🌙× 32192 🌙× 415 🌙× 8 == 123233232

First 20 distinct lunar even numbers:
0 1 2 10 11 12 20 21 22 100 101 102 110 111 112 120 121 122 200 201

First 20 lunar square numbers:
0 1 2 3 4 5 6 7 8 9 100 111 112 113 114 115 116 117 118 119

First 20 lunar factorial numbers:
1 1 1 1 1 1 1 1 1 1 10 110 1110 11110 111110 1111110 11111110 111111110 1111111110 11111111110

First number whose lunar square is smaller than the previous: 1020

Raku

That's not a banana. That's a crescent moon.

# The operators
sub infix:<🌙+> ($a, $b = 0) { # addition
    +([Zmax] ('0'x$b.chars~$a).comb,('0'x$a.chars~$b).comb).join;
}

sub infix:<🌙×> ($a, $b = 9) { # multiplication
    [🌙+] $b.flip.comb.kv.map: -> $k,$v {$a.comb.map(* min $v).join ~ '0'x$k}
}

# The task
for (976, 348), (23, 321), (232, 35), (123, 32192, 415, 8) {
    say '     Lunar add: ' ~ (.join: ' 🌙+ ') ~ ' == ' ~ (.join: ' 🌙+ ').EVAL;
    say 'Lunar multiply: ' ~ (.join: ' 🌙× ') ~ ' == ' ~ (.join: ' 🌙× ').EVAL;
    say '';
}

say "First 20 distinct lunar even numbers:\n" ~ (^Inf).map(* 🌙× 2).unique[^20];
say "\nFirst 20 lunar square numbers:\n"      ~ (my @squares = (^Inf).map:{$_ 🌙× $_})[^20];
say "\nFirst 20 lunar factorial numbers:\n"   ~ (1..*).map({[🌙×] 1..$_})[^20];

# Stretch
say "\nFirst number whose lunar square is smaller than the previous: " ~
(1..Inf).first: {@squares[$_ - 1] > @squares[$_]};
Output:
     Lunar add: 976 🌙+ 348 == 978
Lunar multiply: 976 🌙× 348 == 34876

     Lunar add: 23 🌙+ 321 == 323
Lunar multiply: 23 🌙× 321 == 2321

     Lunar add: 232 🌙+ 35 == 235
Lunar multiply: 232 🌙× 35 == 2332

     Lunar add: 123 🌙+ 32192 🌙+ 415 🌙+ 8 == 32498
Lunar multiply: 123 🌙× 32192 🌙× 415 🌙× 8 == 123233232

First 20 distinct lunar even numbers:
0 1 2 10 11 12 20 21 22 100 101 102 110 111 112 120 121 122 200 201

First 20 lunar square numbers:
0 1 2 3 4 5 6 7 8 9 100 111 112 113 114 115 116 117 118 119

First 20 lunar factorial numbers:
1 1 1 1 1 1 1 1 1 10 110 1110 11110 111110 1111110 11111110 111111110 1111111110 11111111110 111111111100

First number whose lunar square is smaller than the previous: 1020

Uiua

Works with: Uiua version 0.15.0-dev.2
Lunar! ← ⍜∩(⇌-@0°⋕)^0      # binary lunar op
☾      ← Lunar!⬚0↥          # add
☽      ← Lunar!(/(☾˜⊂0)⊞↧)  # multiply

{976_348 23_321 232_35 [123 32192 415 8]}
∵◇(&p $"_ sum = _, product = _"⟜⊃/☾/☽)

&p "\nFirst 20 distinct even:"
&p ⇌◴⍢(⊂☽2⊸⧻|<20⧻◴)[]

&p "\nFirst 20 squares:"
&p ∵☽.⇡20

&p "\nFirst 20 factorials:"
&p ≡(/☽+1⇡)↘1⇡21

&p "\nFirst square smaller than previous:"
&p ⊙◌⍢∩+₁(<∩(☽.))1 0
Output:
[976 348] sum = 978, product = 34876
[23 321] sum = 323, product = 2321
[232 35] sum = 235, product = 2332
[123 32192 415 8] sum = 32498, product = 123233232

First 20 distinct even:
[0 1 2 10 11 12 20 21 22 100 101 102 110 111 112 120 121 122 200 201]

First 20 squares:
[0 1 2 3 4 5 6 7 8 9 100 111 112 113 114 115 116 117 118 119]

First 20 factorials:
[1 1 1 1 1 1 1 1 1 10 110 1110 11110 111110 1111110 11111110 111111110 1111111110 11111111110 111111111100]

First square smaller than previous:
1020

Wren

Library: Wren-math

Whilst we can override the existing '+' and '*' operators by wrapping non-negative integers in a new Lunar class, we can't introduce new ones.

import "./math" for Math, Int

var MOON = "🌙"

class Lunar {
    static zero { Lunar.of(0) }
    static one  { Lunar.of(1) }
    static nine { Lunar.of(9) }

    construct of(n) {
        if (!((n is Num) && n.isInteger && n >= 0)) {
            Fiber.abort("Argument must be a non-negative integer.")
        }
        _n = n
    }

    n { _n }

    getOps_(other) {
        if (!(other is Lunar)) other = Lunar.of(other)
        var op1 = Int.digits(_n)
        var op2 = Int.digits(other.n)
        var c1 = op1.count
        var c2 = op2.count
        if (c1 < c2) {
            op1 = [0] * (c2 - c1) + op1
        } else  if (c2 < c1) {
            op2 = [0] * (c1 - c2) + op2
        }
        return [op1, op2]
    }

    +(other) {
        var ops = getOps_(other)
        var res = (0...ops[0].count).map { |i| Math.max(ops[0][i], ops[1][i]) }.join("")
        return Lunar.of(Num.fromString(res))
    }

    *(other) {
        var ops = getOps_(other)
        var count = ops[0].count
        var lunars = List.filled(count, null)
        var zeros = ""
        for (i in count-1..0) {
            var num = (0...count).map { |j| Math.min(ops[0][i], ops[1][j]) }.join("")
            if (i < count - 1) zeros = zeros + "0"
            lunars[count-1-i] = Lunar.of(Num.fromString(num + zeros))
        }
        return lunars.reduce { |acc, x| acc + x }
    }

    ==(other) { _n == other.n }

    <(other)  { _n < other.n }

    toString { _n.toString }
}

var tests = [ [976, 348], [23, 321], [232, 35], [123, 32192, 415, 8] ]
for (test in tests) {
    var sum  = test.reduce(Lunar.zero) { |acc, x| acc + x }
    var prod = test.reduce(Lunar.nine) { |acc, x| acc * x }
    System.print("Lunar add: %(test.join(" " + MOON + "+ ")) = %(sum)")
    System.print("Lunar mul: %(test.join(" " + MOON + "× ")) = %(prod)\n")
}

System.print("First 20 distinct even lunar numbers:")
var i = 0
var evens = []
while (evens.count < 20) {
    var even = Lunar.of(i) * 2
    var isDistinct = true
    for (j in evens) {
        if (even == j) {
            isDistinct = false
            break
        }
    }
    if (isDistinct) evens.add(even)
    i = i + 1
}
System.print(evens.join(" "))

System.print("\nFirst 20 square lunar numbers:")
System.print((0...20).map { |i| Lunar.of(i) * i }.join(" "))

System.print("\nFirst 20 factorial lunar numbers:")
var fact = Lunar.one
for (i in 1..20) {
    fact = fact * i
    System.write("%(fact) ")
}
System.write("\n\nFirst number whose lunar square is smaller than the previous: ")
var prev = Lunar.zero
i = 1
while (true) {
    var curr = Lunar.of(i) * i
    if (curr < prev) {
        System.print(i)
        break
    }
    prev = curr
    i = i + 1
}
Output:
Lunar add: 976 🌙+ 348 = 978
Lunar mul: 976 🌙× 348 = 34876

Lunar add: 23 🌙+ 321 = 323
Lunar mul: 23 🌙× 321 = 2321

Lunar add: 232 🌙+ 35 = 235
Lunar mul: 232 🌙× 35 = 2332

Lunar add: 123 🌙+ 32192 🌙+ 415 🌙+ 8 = 32498
Lunar mul: 123 🌙× 32192 🌙× 415 🌙× 8 = 123233232

First 20 distinct even lunar numbers:
0 1 2 10 11 12 20 21 22 100 101 102 110 111 112 120 121 122 200 201

First 20 square lunar numbers:
0 1 2 3 4 5 6 7 8 9 100 111 112 113 114 115 116 117 118 119

First 20 factorial lunar numbers:
1 1 1 1 1 1 1 1 1 10 110 1110 11110 111110 1111110 11111110 111111110 1111111110 11111111110 111111111100 

First number whose lunar square is smaller than the previous: 1020
Cookies help us deliver our services. By using our services, you agree to our use of cookies.