0 Members and 2 Guests are viewing this topic.
X-1→X push X 4*X→X ;in code, X is in HL, so I just use add hl,hl \ add hl,hl. This doesn't really count as a multiplication routine, then. Ans+4 ;In code, this is just inc h \ inc h \ inc h \ inc h X/Ans pop X Ans+3 X/Ans Ans+2 X/Ans Ans+1 X/Ans
FPLog88:;Input:; HL is the 8.8 Fixed Point input. H is the integer part, L is the fractional part.;Output:; HL is the natural log of the input, in 8.8 Fixed Point format. ld a,h or l dec hl ret z inc hl push hl ld b,15 add hl,hl jr c,$+4 djnz $-3 ld a,b sub 8 jr nc,$+4 neg ld b,a pop hl push af jr nz,lnx jr nc,$+7 add hl,hl djnz $-1 jr lnx sra h rr l djnz $-4lnx: dec h ;subtract 1 so that we are doing ln((x-1)+1) = ln(x) ld d,h ld e,l inc h call FPDE_Div_HL ;preserves DE, returns AHL as the 16.8 result inc h ;now we are doing x/(3+Ans) inc h inc h call FPDE_Div_HL inc h ;now we are doing x/(2+Ans) inc h call FPDE_Div_HL inc h ;now we are doing x/(1+Ans) call FPDE_Div_HL ;now it is computed to pretty decent accuracy pop af ;the power of 2 that we divided the initial input by ret z ;if it was 0, we don't need to add/subtract anything else ld b,a jr c,SubtLn2 push hl xor a ld de,$B172 ;this is approximately ln(2) in 0.16 FP format ld h,a ld l,a add hl,de jr nc,$+3 inc a djnz $-4 pop de rl l ;returns c flag if we need to round up ld l,h ld h,a jr nc,$+3 inc hl add hl,de retSubtLn2: ld de,$00B1 or a sbc hl,de djnz $-3 retFPDE_Div_HL:;Inputs:; DE,HL are 8.8 Fixed Point numbers;Outputs:; DE is preserved; AHL is the 16.8 Fixed Point result (rounded to the least significant bit) di push de ld b,h ld c,l ld a,16 ld hl,0Loop1: sla e rl d adc hl,hl jr nc,$+8 or a sbc hl,bc jp incE sbc hl,bc jr c,$+5incE: inc e jr $+3 add hl,bc dec a jr nz,Loop1 ex af,af' ld a,8Loop2: ex af,af' sla e rl d rla ex af,af' add hl,hl jr nc,$+8 or a sbc hl,bc jp incE_2 sbc hl,bc jr c,$+5incE_2: inc e jr $+3 add hl,bc dec a jr nz,Loop2;round ex af,af' add hl,hl jr c,$+6 sbc hl,de jr c,$+9 inc e jr nz,$+6 inc d jr nz,$+3 inc a ex de,hl pop de ret
Log_2_88:;Inputs:; HL is an unsigned 8.8 fixed point number.;Outputs:; HL is the signed 8.8 fixed point value of log base 2 of the input.;Example:; pass HL = 3.0, returns 1.58203125 (actual is ~1.584962501...);70 bytes ex de,hl ld hl,0 ld a,d ld c,8 or a jr z,DE_lessthan_1 srl d jr z,logloop-1 inc l rr e jp $-7DE_lessthan_1: ld a,e dec hl or a ret z inc l dec l add a,a jr nc,$-2 ld e,a inc dlogloop: add hl,hl push hl ld h,d ld l,e ld a,e ld b,7 add hl,hl rla jr nc,$+3 add hl,de djnz $-5 adc a,0 add hl,hl rla jr nc,$+5 add hl,de adc a,0 ld e,h ld d,a pop hl rr a jr z,$+7 srl d rr e inc l dec c jr nz,logloop ret
Very nice. A minor optimization: in line 109 you can use rla instead of rl a, since you're not checking that zero flag anywhere.
I'd just create two look-up tables: one for 0<n<1 and another for 1<n<255. Then, branch depending on the MSB of n. Actually, if you compute a reciprocal, you only need one table. Basically, your input really only has 8 significant bits; surely that can be used for an optimization. Your output domain is -5.6<n<5.6.Edit: Use change-of-base rule: It's trivial to compute n-log-base-2, so just compute that then divide by the hardcoded log-base-2 of e value.
Log_2_88_size:;Inputs:; HL is an unsigned 8.8 fixed point number.;Outputs:; HL is the signed 8.8 fixed point value of log base 2 of the input.;Example:; pass HL = 3.0, returns 1.58203125 (actual is ~1.584962501...);averages about 39 t-states slower than original;62 bytes ex de,hl ld hl,0 ld a,d ld c,8 or a jr z,DE_lessthan_1 srl d jr z,logloop-1 inc l rr e jr $-7DE_lessthan_1: ld a,e dec hl or a ret z inc l dec l add a,a jr nc,$-2 ld e,a inc dlogloop: add hl,hl push hl ld h,d ld l,e ld a,e ld b,8 add hl,hl rla jr nc,$+5 add hl,de adc a,0 djnz $-7 ld e,h ld d,a pop hl rr a ;this is right >_> jr z,$+7 srl d rr e inc l dec c jr nz,logloop ret