AbsDayNumToDate en ASM (pour archive)

Pour discuter de l'assembleur
Mesa
Messages : 1093
Inscription : mer. 14/sept./2011 16:59

AbsDayNumToDate en ASM (pour archive)

Message par Mesa »

Code : Tout sélectionner

; DWORD AbsDayNumToDate(DWORD N, DWORD Gregorian, DWORD* Y, DWORD* M, DWORD* D)
;
; This function converts the absolute day number N = 1, 2, ..., 2^32-1 to the adequate date (for the chosen calendar).
;
; Parameters:
;	N - absolute day number,
;	Gregorian - chosen calendar (0 - Julian, 1 - Gregorian),
;	Y - pointer to variable where the calculated year number will be stored,
;	M - pointer to variable where the calculated month number will be stored,
;	D - pointer to variable where the calculated day number will be stored.
;
; Returned values:
;	* 0 for the valid parameters (N, Gregorian),
;	* -1 in opposite case.
Procedure AbsDayNumToDate( N.l, Gregorian.l, Y.l, M.l, D.l)
	;PUSHFD
	;PUSH	ebx ecx edx
	Protected.l tmpeax, tmpecx, tmpedx, tmpeflags, tmp

 EnableASM
	CMP	N, 0							; N <> 0 ; l'année  n'existe pas
	JE	l_absdaynumtodate_error							;

	TEST	Gregorian, -2		; 0 <= Gregorian <= 1
	JNZ	l_absdaynumtodate_error							;

	XOR	ecx, ecx					; ecx := 0
	
	MOV	eax, N					  ; eax := N - 1
	DEC	eax							  ;

	CMP	Gregorian, 0
	JE	l_absdaynumtodate_julian

	gregorian:
	CMP	eax, 1	
	JA	l_absdaynumtodate_nextdays ;Jump short if above (CF=0 and ZF=0).
									      ; 0 <= eax <= 1 (1 <= N <= 2)
		MOV	ecx, M					; M := 12								
		MOV	dword [ecx], 12					;

		ADD	eax, 30					; eax := eax + 30 = N - 1 + 30 = N + 29 

		MOV	ecx, D					; D := eax = N + 29
		MOV	[ecx], eax			;

		MOV	ecx, -5844001   ; -k*G - 1		; ecx := -kG - 1 = -5844001
; 		Global k	= 30
;     Global J	= 194796		; The constants J and G are equal to the numbers of the complete years
;     Global G	= 194800		; of the Julian and Gregorian calendars respectively contained in the 
				                    ; time interval given by "Great Cycle" T.

		JMP	l_absdaynumtodate_yearr

	nextdays:							  ; eax > 1 (N > 2)
		SUB	eax, 2						; eax := eax - 2 = N - 1 - 2 = N - 3 
		XOR	edx, edx					;
; 		Global C1	= 365			; Number of days in a normal year.
;     Global C4	= 4*C1 + 1	= 1461	; Number of days in the 4-year cycle (base cycle of the Julian calendar).		
;     Global C100	= 25*C4 - 1	= 36524; Number of days in a "normal" century in the Gregorian calendar
; 				                ; (i.e. century ending with a normal, 365-day, year).
;     Global C400	= 4*C100 + 1	= 146097	; Number of days in the complete 400-year cycle of the Gregorian calendar.
 

		MOV	ecx, 146097   ;C400					; eax := E(eax / C400) = E((N - 3) / C400)
		DIV	ecx						; edx := eax mod C400 = (N - 3) mod C400

		LEA	eax, [eax + 4*eax]	; eax := 5*eax = 5*E((N - 3) / C400)
		LEA	eax, [eax + 4*eax]	; eax := 5*eax = 5*(5*E((N - 3) / C400)) =
						                ; = 25*E((N - 3) / C400)

		SHL	eax, 4						  ; eax := 16*eax = 16*(25*E((N - 3) / C400)) =
									          ; = 400*E((N - 3) / C400)

		XCHG	ecx, eax					; ecx := eax = 400*E((N - 3) / C400)
									 
	
		XCHG	eax, edx					; eax := edx = (N - 3) mod C400
							 

		centuries:						;
		CMP	eax, 36524    ; C100				

			JB	l_absdaynumtodate_julian	;Jump short if below (CF=1).
								
			ADD	ecx, 100				
			SUB	eax, 36524    ; C100				
								
			CMP	eax, 36524    ; C100				; (eax, ecx) := P(eax, ecx) = 
			JB	l_absdaynumtodate_julian		;             = P((N - 3) mod C400, 400*E((N - 3) / C400)) =
 									      ; = (N100, Y100)
			ADD	ecx, 100				
			SUB	eax, 36524    ; C100				
									
			CMP	eax, 36524    ; C100				
			JB	l_absdaynumtodate_julian					
 									
			ADD	ecx, 100				
			SUB	eax, 36524    ; C100				
 
julian:
									;                             /
									;                             |  (N - 1, 0)                                 ; Gregorian = 0
									; (N100, Y100) = (eax, ecx) = <
									;                             |  P((N - 3) mod C400, 400*E((N - 3) / C400)) ; Gregorian = 1
									;                             \
    PUSH ecx
		XOR	edx, edx					
		MOV	ecx, 1461 ; C4	; eax := E(eax / C4) = E(N100 / C4)
		DIV	ecx				; edx := eax mod C4 = N100 mod C4
		POP ecx
		
		SHL	eax, 2		; eax := 4*eax = 4*E(N100 / C4)

		ADD	ecx, eax	; ecx := ecx + eax = Y100 + 4*E(N100 / C4)

		years:							
			INC	ecx					
			
			CMP	edx, 365 ; C1					
			JB	l_absdaynumtodate_md					
								
			SUB	edx, 365 ; C1					
									
			INC	ecx			              ; (edx, ecx) := Q(edx, ecx) =
			CMP	edx, 365 ; C1					; = Q(N100 mod C4, Y100 + 4*E(N100 / C4)) =
			JB	l_absdaynumtodate_md	; = (N', Y*)
									
			SUB	edx, 365 ; C1					
										
			INC	ecx					
			CMP	edx, 365 ; C1					
			JB	l_absdaynumtodate_md					
									
			SUB	edx, 365 ; C1					
									
			INC	ecx					

	md:
		INC	edx						; edx := edx + 1 = N' + 1
	
		;sauvegarde
		MOV tmpeax, eax
		MOV tmpecx, ecx
		MOV tmpedx, edx

		IsLeapYear(tmpecx, Gregorian)			; eax := IsLeapYear(ecx=year, Gregorian) =
		                                  ; = IsLeapYear(Y*, Gregorian)
    MOV tmpeax, eax

		;DayNumToMD(n.l, LeapYearFlag.l, M.l, D.l)
    DayNumToMD(tmpedx, tmpeax, M, D)

		MOV ecx, tmpecx 
		MOV edx, tmpedx
		
		CMP	Gregorian, 0
		JE	l_absdaynumtodate_julianyears

		gregorianyears:					
			SUB	ecx, 120  ;k*(G - J)				;k*(G - J)=180
									  ; ecx := ecx - kJ - k(G - J)[Gregorian = 1] =
		julianyears:		;      = Y* - kJ - k(G - J)[Gregorian = 1] = 
			SUB	ecx, 5843880  ;k*J				; = Y';k*J=5843880

			CMP	ecx, 0
			JG	l_absdaynumtodate_yearr
									  ; ecx <= 0 (Y' <= 0)

			DEC	ecx				; ecx := ecx - 1 = Y' - 1 = Y' - [Y' <= 0]

		yearr:
			MOV	eax, Y		; Y := ecx
			MOV	[eax], ecx				

		XOR	eax, eax
		JMP	l_absdaynumtodate_theend

	error:
		MOV	eax, -1

	theend:

	;POP	edx ecx ebx
	;POPFD

	DisableASM
ProcedureReturn

EndProcedure
M.
Dernière modification par Mesa le jeu. 19/déc./2013 18:56, modifié 2 fois.
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: AbsDayNumToDate en ASM (pour archive)

Message par falsam »

Le resultat

Code : Tout sélectionner

Debug AbsDayNumToDate(2135207292,1,@Y, @M, @D );  N, Gregorian, Y, M, D
Debug D
Debug M
Debug Y 
N'est pas du tout le même que

Code : Tout sélectionner

Debug Day(2135207292)
Debug Month(2135207292)
Debug Year(2135207292)
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Mesa
Messages : 1093
Inscription : mer. 14/sept./2011 16:59

Re: AbsDayNumToDate en ASM (pour archive)

Message par Mesa »

C'est tout à fait normal car le "2135207292" est un nombre de jours à partir du 30 Dec -5844001 (environ) alors que les fonctions DATE de PureBasic utilisent un nombre de secondes écoulées à partir du '01/01/1970 0:00:00'


M.
Répondre