Day of the week using offset of arrays

Started by ilian007, November 09, 2009, 06:44:30 AM

Previous topic - Next topic

ilian007

Hi we have to write a program which will calculate the day of the week from Jan.1.1901 to Dec.12.2099. We have to use arrays.
first we have to input:
Month
Date
Year
then we have to check if the input is correct

I did some coding but have no idea what I am doing really ... I was reading online for the mathematical methods there are a few. I found months have some codes :
Jan Feb Mar Apr. May Jun Jul Ago Sept Oct Nov Dec
6      2    2     5      0     3    5    1    4     6    2    4

In the moment I dont know how exactly to setup an array of Days and months and I dont know how exactly to input the data and check if correct ...
here is the code I have so far ... it is not a full code and is not working. I was trying to input some year and print it back on the screen couldnt do that .. since I can not put the value of AX to anything ....

;===================================================================
             .MODEL  MEDIUM,BASIC
.STACK 256
;===================================================================
                                       ;PROCEDURES TO
             
   
   EXTRN   CLEAR:FAR   ;CLEAR SCREEN
   EXTRN   NEWLINE:FAR    ;DISPLAY NEWLINE CHARACTER
           EXTRN   GETDEC$:FAR   ;GET 16-BIT DECIMAL FROM KBD
   EXTRN   PUTDEC$:FAR   ;DISPLAY 16-BIT DECIMAL INT
   EXTRN   GETDEC:FAR
   EXTRN   PUTDEC:FAR
   EXTRN   PUTBIN:FAR   ;DISPLAY 16BIT BINARY INT
           EXTRN   PUTOCT:FAR     ;DISPLAY 8-BIT NUMBER
   EXTRN   PUTSTRNG:FAR   ;DISPLAY CHARACTER STRING


;===================================================================
;DATA  S E G M E N T   D E F I N I T I O N
;
  .DATA
monthname DB 'JAN$FEB$MAR$APR$MAY$JUN$JUL$AUG$SEP$OCT$NOV$DEC$'
dayname   DB 'SUN$Mon$TUE$THU$FRI$SAT$'
startday  DB 0
month   db 0
date   db 0
year   db 0


   

.CONST

enterMonth DB 'Please Enter month number 1-12 : '
enterDate DB 'Please enter date 0 to 28,29,30,31: '
enteryear DB 'Please enter year from 1901 to 2099: '
ENTERED      DB 'you have entered: '

;===================================================================
;C O D E   S E G M E N T   D E F I N I T I O N
;
            .CODE
    ASSUME  DS:DGROUP
;===================================================================
MAIN PROC

        MOV     AX,DGROUP     ;SET DS-REGISTER TO POINT TO
        MOV     DS,AX               ;CONSTANT DATA SEGMENT
MOV     ES,AX    ;SET ES-REGISTER
CALL    CLEAR
START:
CALL    NEWLINE
        LEA     DI,OFFSET enterMonth ; Prompt for month
        MOV     CX,SIZEOF entermonth ;
CALL    PUTSTRNG
CALL    GETDEC$     ; GET 16-BIT NUMBER FROM KBD
MOV     month,0
XCHG ax,month

mov     ax,0
CALL    NEWLINE
        LEA     DI,OFFSET enterdate ; Prompt for month
        MOV     CX,SIZEOF enterdate ;
CALL    PUTSTRNG
CALL    GETDEC$
ADD date,ax

mov ax,0
CALL    NEWLINE
        LEA     DI,OFFSET enteryear ; Prompt for month
        MOV     CX,SIZEOF enteryear ;
CALL    PUTSTRNG
CALL    GETDEC$        
ADD year,ax

MOV AX, month
CALL PUTDEC
MOV AX, date
call putdec
MOV ax, year
call    putdec


.EXIT
MAIN ENDP                       
        END MAIN


THAnks


Added code tags



dedndave

hi Ilian - use the forum search tool - there are complete algorithms for this

ilian007

I tried but there are a few which are too complicated for my level of assembly :( (or maybe I didnt find the ones which are close to my knowledge) Some of them were 32bit others using clock of the computer as start date. My problem is how to setup an array and how to connect it to the data from input (operator). I have some ideas of using AL, CX, and etc but not very sure how to do it ..

ilian007

Another problem for me is how to verify if the input data is correct..
for example year: 1925 month Feb Day: 30th to say ... incorrect day for Feb: 30th ...

MichaelW

Ilian,

Much of the code posted here tends to be optimized for speed, and this makes understanding how the code works difficult. I think you should keep the algorithm and the code as simple as possible. One possibility for a simple algorithm would be to calculate the day of week relative to January 1, 1901. To do this you could start by calculating for the target date the number of days since January 1, 1901. Since January 1, 1901 is a Tuesday, and assuming that the days of the week are numbered from 0 (Sunday) to 6 (Saturday), you would add 2 to the number of days then calculate the day of week as (number of days) MOD 7. For example, assuming a target date of January 1, 1902, the number of days since January 1, 1901 is 365.

365 + 2 = 367
367 MOD 7 = 3

So January 1, 1902 is a Wednesday.
eschew obfuscation

ilian007

Thank you Michael I kind of understand the mathematical algorithm to do the problem. However I have dificulties understand and create an array which will consist the Months and the days and playing arrround with their offsets. Furthermore, I have dificulties creating a procedure which will verify the input data if correct and in range.

I was reading about arrays and found best is to use SI or DI registers. MOV DI, X and then ADD DI, 3 and then MOV AX, DI (which should give me the offset of [X+3] still cant get it how exactly to use it for solving my problem ..... Sorry if I sound weird ... I am a beginner ..

can I do something like this: Monthname DB 'jan$Feb$Mar$Apr$'

and then If I have to calculate April to do :
Mov DI, monthname
ADD DI, 3
MOV AX,DI

Is that giving me Month April in AX ?

THanks

FORTRANS

Hi,

   You are getting the idea, sort of.  BX and BP are the base
addressing registers.  DI and SI are the index addressing
registers.  If you have your array of months:


MonthName DB    'Jan$Feb$Mar$Apr$'May$Jun$'
        DB      'Jul$Aug$Sep$Qct$Nov$Dec$'


   Then each array member is four bytes long.  So for April:


;    April is the fourth month, so the user will enter 4 if they want April.
; Say that you have it in the SI register somehow.
        SUB     SI,1    ; Take off one as arrays start with a zero offset to the first element.
                        ; So three points to the fourth element 'Apr$'.
        SHL     SI,1    ; \ These are the equivalent of multiplying by four,
        SHL     SI,1    ; / which is the size of the array elements.
                        ; Then add in the array address.
        ADD     SI,OFFSET MonthName
                        ; Now SI points to the fourth element.


Regards,

Steve N.

MichaelW

Here is another simple example that displays the month and the days per month (for non-leap years).

.model small
.stack
.data

    daysPerMonth dw 31,28,31,30,31,30,31,31,30,31,30,31

    monthName    db 'JAN$FEB$MAR$APR$MAY$JUN$JUL$AUG$SEP$OCT$NOV$DEC$'

    NL           db 13,10,'$'

.code

;=========================================================================

;--------------------------------------------------------------------
; This proc displays the value of AX as an unsigned decimal integer.
;--------------------------------------------------------------------

PrintDec proc uses ax bx cx dx

    mov bx,10                   ; init divisor
    mov cx,0                    ; zero digit counter
  @@:
    mov dx,0                    ; zero MSW of dividend
    div bx                      ; divide value by 10
    push dx                     ; push remainder
    inc cx                      ; increment digit count
    or  ax,ax                   ; repeat if quotient > 0
    jnz @B
  @@:
    pop dx                      ; pop digit off stack
    add dl,30h                  ; convert to ascii
    mov ah,2                    ; display
    int 21h
    loop @B                    ; repeat CX times
    ret

PrintDec endp

;=========================================================================

;-------------------------------------------------------------
; This proc displays the string at the index specified by AX.
;-------------------------------------------------------------

PrintMonth proc uses dx

    shl ax, 1                   ; calc string offset as index * 4
    shl ax, 1
    mov dx, ax                  ; move offset into DX
    add dx, OFFSET monthName    ; add offset address of array
    mov ah, 9                   ; display string
    int 21h
    ret

PrintMonth endp

;=========================================================================

.startup

    xor cx, cx                  ; zero starting index
  @@:
    mov ax, cx
    call PrintMonth

    mov dx, ' '                 ; use a space as a separator
    mov ah, 2
    int 21h

    inc cx                      ; increment index
    cmp cx, 12
    jb  @B                      ; repeat until index = 12

    mov dx, OFFSET NL           ; move the cursor to the next line
    mov ah, 9
    int 21h

    ;--------------------------------------------------------
    ; In 16-bit code indirect-memory operands can use a base
    ; register (BX or BP), an index register (SI or DI), or
    ; one of each, combined with an optional displacement.
    ;--------------------------------------------------------

    mov bx, OFFSET daysPerMonth ; load offset address of array
    xor si, si                  ; zero starting index
    mov cx, 12                  ; load count of months
  @@:
    ;--------------------------------------------
    ; The [bx+si] is an indirect-memory operand.
    ;--------------------------------------------
    mov ax, [bx+si]             ; get word at index
    call PrintDec

    mov dx, ' '                 ; use a space as a separator
    mov ah, 2
    int 21h
    mov dx, ' '                 ; and anoter space for alignment
    mov ah, 2
    int 21h

    add si, 2                   ; adjust index by size of elements
    loop @B                     ; repeat CX times

    mov dx, OFFSET NL           ; move the cursor to the next line
    mov ah, 9
    int 21h

    mov ah, 0                   ; wait for key press before exit
    int 16h

;=========================================================================

.exit
end

eschew obfuscation

ilian007

Thank you guys I will continue doing some part of my coding tonight and then maybe I will be able to clarify the info for myself and ask some more clear questions. In the moment your answers seems good , but for much higher level of assembly from what I study :). I believe my program should be arround 10 - 15 lines of code. Still have to manage how to do the  input and how to verify the data entered from the operator. I have to use getdec for input of month, date and year and verify if it is correct entry. After I do the input and  the verification, I will have to continue and do the rest of the calculation. 
Main points in the moment are:
1. Setup an array for the program
2. Input of Year, Month Date using Getdec
3. Verify the input if not correct input return to the start of the program

Thanks will write again later :)

MichaelW

QuoteI believe my program should be arround 10 - 15 lines of code.

That would be difficult even in a high-level language, but in assembly language I think you should expect at least 150 lines of code.
eschew obfuscation

ilian007

Yes MIchael that is true I said that meaning that it should be something simple .. at least I hope for that :))

I want first to setup the arrays and the input + verification. the rest should be just the mathematical method I guess. ....

FORTRANS

Hi,

   You should write out what you think should happen in a flow chart,
pseudo-code, or another language like BASIC to code against.  It is
a lot easier if you have a detailed road map when programming in
assembler.  If an algorithm does not make sense to you in plain
language, you may not recognize problems or incorrect actions in
a new programming environment.

'luck,

Steve

ilian007

Thanks Fortrans I was about to do something like this. Now it is a little bit more clear for me. The mistake I was doing was I was trying to mov AX in the varible 'months' which is Byte ... not very smart of me :)

Thanks to everybody
I will do some coding now and will see if will make it work :)

ilian007

I have it work :)

I would like to ask :

Is there any way to interrupt the program while input the data ?
For example

Please enter month: 2

please enter days:  <-------------- I am with windows 7 32 bit and in CMD ... tried Ctrl+c Ctrl+z ctrl+break    none of them is taking me out the program

thank you

MichaelW

QuoteIs there any way to interrupt the program while input the data ?

Based on my tests of GETDEC$ and GETSTRNG I suspect that none of the IO.LIB input procedures provide any way to do this. Tracing through the code for GETDEC$ it looks like the procedure uses only BIOS calls. An input procedure based on the more recent DOS functions will respond to Ctrl-C, as well as accept a wider range of inputs. For example:

;=========================================================================
.model small, c
.386
.stack
;=========================================================================
.data
    buffer db 128 dup(0)
.code
;=========================================================================

HSTDIN   EQU 0
HSTDOUT  EQU 1

; -------------------------------------------------------------
; This proc calls the Read File or Device function to read
; up to <blen> bytes from STDIN and store them in the
; specified buffer.
; -------------------------------------------------------------

stdin proc uses bx cx dx npdest:WORD, blen:WORD
    mov bx, HSTDIN
    mov cx, blen
    mov dx, npdest
    mov ah, 3fh
    int 21h
    mov bx, npdest
  @@:                         ; Scan for CR and replace with null
    cmp BYTE PTR [bx], 0
    je  @F
    cmp BYTE PTR [bx], 13
    je  @F
    inc bx
    jmp @B
  @@:
    mov BYTE PTR [bx], 0
    ret
stdin endp

;=========================================================================
.startup
;=========================================================================

    invoke stdin, addr buffer, sizeof buffer

.exit
end

eschew obfuscation