| 
 Leap days (or not) in February for PBDOS - Dale Yarker -  08.03.2025
 
 'DECLARE not needed if FUNCTION source is before the CALL
 'here the CALL is in PBMAIN
 'I call it bottom up because PBMAIN is last and flow goes up
 '
 'Pretty sure PUSHes and POPs not needed in FUNCTION
 'They will be needed to use "inside" code in-line with BASIC
 '
 'Used PBCC v6 to test. I no longer have PBDOS available.
 function Tage_im_Februar(byval iJahr as integer) as integer
 local FebruarTage as integer
 ! push ax
 ! mov FebruarTage, 28&  'not a leap year, pre-set to 28
 ! mov ax, 1582%
 ! cmp ax, iJahr
 ! jge Julian
 ! mov ax, 3%
 ! and ax, iJahr    'conditionally equivalent MOD 4
 ! jz MOD100        '0 is possible leap year
 ! jmp Done
 MOD100:
 ! push bx          'for divisor
 ! push dx          'for high part of dividend, remainder (MOD)
 ! xor dx, dx
 ! mov ax, iJahr
 ! mov bx, 100%
 ! div bx
 ! cmp dx, 0%    'does MOD 100 = 0 ?
 ! pop dx
 ! pop bx
 ! jz MOD400        '0 is possibly not a leap year
 ! jmp Is29Days      'non 0 is a leap year
 MOD400:
 ! and ax, 3%    'EAX has Year\100, so conditionally equivalent MOD 400
 ! jnz Done
 Julian:
 ! mov ax, 3%
 ! and ax, iJahr
 ! jnz Done
 Is29Days:
 ! mov FebruarTage, 29%
 Done:
 ! pop ax
 function = FebruarTage
 end function
 function pbmain () as long 'put only to demonstrate Tage_im_Februar
 local iJahr as integer
 iJahr = 2000
 print Tage_im_Februar(iJahr); " 2000, divisible by 400, is leap"
 iJahr = 2100
 print Tage_im_Februar(iJahr); " 2100, divisible by 100 not 400, not leap"
 iJahr = 2104
 print Tage_im_Februar(iJahr); " 2104, divisible by 4 not 100, is leap"
 iJahr = 2103
 print Tage_im_Februar(iJahr); " 2103, not divide 4, not leap
 print "julian, did not check rule for prior to Gregorian myself"
 iJahr = 1204
 print Tage_im_Februar(iJahr); " 1204, divisible by 4, is leap
 iJahr = 1201
 print Tage_im_Februar(iJahr)  " 1201, not divisible by 4, not leap
 waitkey$
 end function
 
 
 RE: Leap days (or not) in February for PBDOS - Andy Dee -  08.03.2025
 
 Thanks a lot, Dale.
 
 I converted everything to the syntax and rules of PB 3.5 and it workg fine!
 
 
 Code: '- 08.03.2025 - Dales work with syntax of PB 3.5 
 $Dim All
 $Compile exe
 
 Declare _
 Function iTage_im_Februar(byval iJahr as integer) as integer
 
 Function iTage_im_Februar(byval iJahr as integer) as integer
 Dim iFebruarTage As Local Integer
 
 ! push ax
 ! mov iFebruarTage, 28%              ; not a leap year, pre-set to 28
 ! mov ax, 1582%
 ! cmp ax, iJahr
 ! jge Julian
 ! mov ax, 3%
 ! and ax, iJahr                      ; conditionally equivalent MOD 4
 ! jz MOD100                          ; 0 is possible leap year
 ! jmp Done
 MOD100:
 ! push bx                            ; for divisor
 ! push dx                            ; for high part of dividend,
 ' remainder (MOD)
 ! xor dx, dx
 ! mov ax, iJahr
 ! mov bx, 100%
 ! div bx
 ! cmp dx, 0%                         ; does MOD 100 = 0 ?
 ! pop dx
 ! pop bx
 ! jz MOD400                          ; 0 is possibly not a leap year
 ! jmp Is29Days                       ; non 0 is a leap year
 MOD400:
 ! and ax, 3%                         ; AX has Year\100, so conditionally
 ' equivalent MOD 400
 ! jnz Done
 Julian:
 ! mov ax, 3%
 ! and ax, iJahr
 ! jnz Done
 Is29Days:
 ! mov iFebruarTage, 29%
 Done:
 ! pop ax
 function = iFebruarTage
 End Function
 
 Function pbMain () as long 'put only to demonstrate Tage_im_Februar
 Dim iJahr As Local Integer
 
 iJahr = 2000
 print iTage_im_Februar(iJahr); " 2000, divisible by 400, is leap"
 iJahr = 2100
 print iTage_im_Februar(iJahr); " 2100, divisible by 100 not 400, not leap"
 iJahr = 2104
 print iTage_im_Februar(iJahr); " 2104, divisible by 4 not 100, is leap"
 iJahr = 2103
 print iTage_im_Februar(iJahr); " 2103, not divide 4, not leap
 print "julian, did not check rule for prior to Gregorian myself"
 iJahr = 1204
 print iTage_im_Februar(iJahr); " 1204, divisible by 4, is leap
 iJahr = 1201
 print iTage_im_Februar(iJahr)  " 1201, not divisible by 4, not leap
 end function
 
 pbMain
 The output is the following:
 
 Code: 29  2000, divisible by 400, is leap28  2100, divisible by 100 not 400, not leap
 29  2104, divisible by 4 not 100, is leap
 28  2103, not divide 4, not leap
 julian, did not check rule for prior to Gregorian myself
 29  1204, divisible by 4, is leap
 28  1201, not divisible by 4, not leap
This helps me a lot, Dale!
 
 
 RE: Leap days (or not) in February for PBDOS - Andy Dee -  09.03.2025
 
 Bit optimized routines, regarding to your thoughts:
 
 
 Code: Declare _FUNCTION iFeb(ByVal iJahr As Integer)        As Integer
 '----------------------------------------------------------------------------
 ' Optimize the BASIC code for speed
 FUNCTION iFeb(ByVal iJahr As Integer) Public As Integer
 '--------------------------------------------------------------------------
 ' Use a temporary variable to reduce calculationtime
 Dim iJahriDiv4 As Local Integer
 '--------------------------------------------------------------------------
 ' Optimize the BASIC's mathematics - thanks to Dale Yarker
 $If 0
 Arithmetic ops by powers of 2 can be done a bit faster by not using
 *, \ or MOD (likely you know of 2 them). For example:
 X * 4 can be SHIFT LEFT X, 2
 X \ 4 can be SHIFT RIGHT X, 2
 X MOD 4 can be X AND 3
 Those can be done in BASIC code so difference between BASIC and ASM
 timing may be made smaller.
 MOD is a divide with the remainder returned instead of the quotient.
 Your BASIC code can be quicker with MOD 100 and MOD 400 than 2 divides
 by 100 and 2 divides by 400.
 In ASM the DIV instruction returns both quotient and remainder. 100 is
 not a power 0f 2, so had to divide by 100. The remainder used as
 MOD 100 and quotient used with X AND as MOD 400.
 The 1,15 times faster for 1204 and 1201 shows how small the difference
 is between MOD and AND.)
 $EndIf
 iJahriDiv4  = iJahr
 SHIFT RIGHT    iJahriDiv4, 2%
 if iJahr < 1582% then
 Function = 29% _
 + ((iJahr AND 3)<>0%)
 else
 Function = 29% _
 + ( _
 (iJahr/4%) <> iJahriDiv4  _
 OR _        _
 (iJahr/100%)=(iJahr\100%) _
 AND _
 (iJahr/400%)<>(iJahr\400%) _
 )
 end if
 END FUNCTION
 Declare _
 Function iTage_im_Februar(byval iJahr as integer) as integer
 '----------------------------------------------------------------------------
 ' Optimize the BASIC code for speed
 Function iTage_im_Februar(byval iJahr as integer) as integer
 Dim iFebruarTage As Local Integer
 ! mov iFebruarTage, 28%              ; not a leap year, pre-set to 28
 ! mov ax, 1582%
 ! cmp ax, iJahr
 ! jge Julian
 ! mov ax, 3%
 ! and ax, iJahr                      ; conditionally equivalent MOD 4
 ! jz MOD100                          ; 0 is possible leap year
 ! jmp Done
 MOD100:
 ' remainder (MOD)
 ! xor dx, dx
 ! mov ax, iJahr
 ! mov bx, 100%
 ! div bx
 ! cmp dx, 0%                        ; does MOD 100 = 0 ?
 ! jz MOD400                          ; 0 is possibly not a leap year
 ! jmp Is29Days                      ; non 0 is a leap year
 MOD400:
 ! and ax, 3%                        ; AX has Year\100, so conditionally
 ' equivalent MOD 400
 ! jnz Done
 Julian:
 ! mov ax, 3%
 ! and ax, iJahr
 ! jnz Done
 Is29Days:
 ! mov iFebruarTage, 29%
 Done:
 function = iFebruarTage
 End Function
 
 
 |