RosettaCodeData/Task/Haversine-formula/X86-Assembly/haversine-formula.x86
Ingy döt Net d066446780 langs a-z
2013-04-10 22:43:41 -07:00

85 lines
6 KiB
Text

0000 .model tiny
0000 .code
.486
org 100h ;.com files start here
0100 9B DB E3 start: finit ;initialize floating-point unit (FPU)
;Great circle distance =
; 2.0*Radius * ASin( sqrt( Haversine(Lat2-Lat1) +
; Haversine(Lon2-Lon1)*Cos(Lat1)*Cos(Lat2) ) )
0103 D9 06 0191r fld Lat2 ;push real onto FPU stack
0107 D8 26 018Dr fsub Lat1 ;subtract real from top of stack (st(0) = st)
010B E8 0070 call Haversine ;(1.0-cos(st)) / 2.0
010E D9 06 0199r fld Lon2 ;repeat for longitudes
0112 D8 26 0195r fsub Lon1
0116 E8 0065 call Haversine ;st(1)=Lats; st=Lons
0119 D9 06 018Dr fld Lat1
011D D9 FF fcos ;replace st with its cosine
011F D9 06 0191r fld Lat2
0123 D9 FF fcos ;st=cos(Lat2); st(1)=cos(Lat1); st(2)=Lats; st(3)=Lons
0125 DE C9 fmul ;st=cos(Lat2)*cos(Lat1); st(1)=Lats; st(2)=Lons
0127 DE C9 fmul ;st=cos(Lat2)*cos(Lat1)*Lats; st(1)=Lons
0129 DE C1 fadd ;st=cos(Lat2)*cos(Lat1)*Lats + Lons
012B D9 FA fsqrt ;replace st with its square root
;asin(x) = atan(x/sqrt(1-x^2))
012D D9 C0 fld st ;duplicate tos
012F D8 C8 fmul st, st ;x^2
0131 D9 E8 fld1 ;get 1.0
0133 DE E1 fsubr ;1 - x^2
0135 D9 FA fsqrt ;sqrt(1-x^2)
0137 D9 F3 fpatan ;take atan(st(1)/st)
0139 D8 0E 019Dr fmul Radius2 ;*2.0*Radius
;Display value in FPU's top of stack (st)
=0004 before equ 4 ;places before
=0002 after equ 2 ; and after decimal point
=0001 scaler = 1 ;"=" allows scaler to be redefined, unlike equ
rept after ;repeat block "after" times
scaler = scaler*10
endm ;scaler now = 10^after
013D 66| 6A 64 push dword ptr scaler;use stack for convenient memory location
0140 67| DA 0C 24 fimul dword ptr [esp] ;st:= st*scaler
0144 67| DB 1C 24 fistp dword ptr [esp] ;round st to nearest integer
0148 66| 58 pop eax ; and put it into eax
014A 66| BB 0000000A mov ebx, 10 ;set up for idiv instruction
0150 B9 0006 mov cx, before+after;set up loop counter
0153 66| 99 ro10: cdq ;convert double to quad; i.e: edx:= 0
0155 66| F7 FB idiv ebx ;eax:= edx:eax/ebx; remainder in edx
0158 52 push dx ;save least significant digit on stack
0159 E2 F8 loop ro10 ;cx--; loop back if not zero
015B B1 06 mov cl, before+after;(ch=0)
015D B3 00 mov bl, 0 ;used to suppress leading zeros
015F 58 ro20: pop ax ;get digit
0160 0A D8 or bl, al ;turn off suppression if not a zero
0162 80 F9 03 cmp cl, after+1 ;is digit immediately to left of decimal point?
0165 75 01 jne ro30 ;skip if not
0167 43 inc bx ;turn off leading zero suppression
0168 04 30 ro30: add al, '0' ;if leading zero then ' ' else add 0
016A 84 DB test bl, bl
016C 75 02 jne ro40
016E B0 20 mov al, ' '
0170 CD 29 ro40: int 29h ;display character in al register
0172 80 F9 03 cmp cl, after+1 ;is digit immediately to left of decimal point?
0175 75 04 jne ro50 ;skip if not
0177 B0 2E mov al, '.' ;display decimal point
0179 CD 29 int 29h
017B E2 E2 ro50: loop ro20 ;loop until all digits displayed
017D C3 ret ;return to OS
017E Haversine: ;return (1.0-Cos(Ang)) / 2.0 in st
017E D9 FF fcos
0180 D9 E8 fld1
0182 DE E1 fsubr
0184 D8 36 0189r fdiv N2
0188 C3 ret
0189 40000000 N2 dd 2.0
018D 3F21628D Lat1 dd 0.63041 ;36.12*pi/180
0191 3F17A4E8 Lat2 dd 0.59236 ;33.94*pi/180
0195 BFC19F80 Lon1 dd -1.51268 ;-86.67*pi/180
0199 C004410B Lon2 dd -2.06647 ;-118.40*pi/180
019D 46472666 Radius2 dd 12745.6 ;6372.8 average radius of Earth (km) times 2
;(TASM isn't smart enough to do floating point constant calculations)
end start