forked from microsoft/GW-BASIC
-
Notifications
You must be signed in to change notification settings - Fork 0
/
MATH2.ASM
1883 lines (1813 loc) · 69.8 KB
/
MATH2.ASM
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
SUBTTL $FIDIG ADD TEXT DIGIT TO CURRENT ACCUMULATED NUMBER
;***************************************************************
;
; $FIDIG CONVERTS DIGIT POINTED TO BY (BX) TO BINARY
; VALUE AND ADDS TO NUMBER ACCUMULATED. AT THE
; APPROPRIATE TIMES CONVERSION WILL TAKE
; PLACE TO THE NEXT HIERARCHY OF NUMBERS,I.E.
; INTEGER-SINGLE PRECISION-DOUBLE PRECISION.
; CALLING SEQUENCE: CALL $FIDIG
; WITH (BX) POINTING TO NUMBER IN THE
; TEXT BUFFER. NUMBER IS ACCUMULATED IN THE FAC.
;
;****************************************************************
;******************************************************************
;AS $FIDIG IS ENTERED CF=1 AND (DI) WILL HOLD PLACES TO THE RIGHT OF
;DECIMAL POINT (IF DECIMAL POINT HAS OCCURRED).(CX) WILL BE EITHER
;ALL BITS SET OR ALL BITS CLEARED. ALL BITS SET INDICATES A DECIMAL
;POINT HAS NOT BEEN SEEN YET AND (CX)=0 INDICATES D. P. SEEN
;******************************************************************
$FIDIG: ADC DI,CX ;(DI) INCREMENTED ONLY IF D.P. SEEN
PUSH BX ;MUST NOW SAVE ALL NECESSARY REGS.
PUSH DI
PUSH CX
SUB AL,LOW "0" ;SUBTRACT OUT ASCII BIAS
PUSH AX ;SAVE ON STACK
CALL $GETYP ;SET CONDITION CODES
POP AX ;RECALL DIGIT
CBW ;ZERO AH
JNS FI05 ;MUST BE S.P. OR D.P. ALREADY
MOV BX,WORD PTR $FACLO ;FETCH THE INTEGER ALREADY ACCUM.
CMP BX,3277D ;IS IT ALREADY TOO BIG TO ADD
;ANOTHER DIGIT TO?
JNB FFI10 ;IF SO GO MAKE S.P. FIRST
MOV CX,BX ;SAVE ORIGINAL (BX)
SHL BX,1 ;(BX)=(BX)*2
SHL BX,1 ;(BX)=(BX)*4
ADD BX,CX ;(BX)=(BX)*5
SHL BX,1 ;(BX)=(BX)*10
ADD BX,AX ;ADD IN THE DIGIT
JS FFI10 ;IF SF=1 WE HAVE 32768 OR 32769
MOV WORD PTR $FACLO,BX ;STORE IN $FAC
JMP SHORT FI50
FI05: ;TO GET HERE NUMBER WAS ALREADY S.P. OR D.P.
PUSH AX ;SAVE THE NUMBER
JB FFFI20 ;IT'S CURRENTLY SINGLE PRECISION
JMP SHORT FI40 ;DOUBLE PRECISION
FFI10: ;TO GET HERE NUMBER WAS PREVIOUSLY AN INTEGER BUT HAS
;GROWN TOO LARGE - MUST MAKE IT SINGLE PRECISION
PUSH AX ;SAVE THE NUMBER
CALL $CSI ;CONVERT INTEGER TO S.P.
JMP SHORT FI30 ;MUL BY 10 AND ADD IN DIGIT
FFFI20: ;TO GET HERE NUMBER WAS ALREADY SINGLE PRECISION
;MUST CHECK TO SEE IF ACCURACY MIGHT BE LOST IF WE
;MULTIPLY OUR FAC BY 10,I.E. FAC MUST BE SMALLER
;THAN 1000000.
MOV WORD PTR $DBUFF+4,22000
MOV WORD PTR $DBUFF+6,112164
MOV BX,OFFSET $DBUFF+6
CALL $COMPM ;COMPARE TO $FAC
JNS FI35 ;GO DO D.P. IF TOO LARGE FOR S.P.
FI30: CALL $MUL10 ;MULTIPLY $FAC BY 10
POP DX ;RECALL DIGIT
PUSH WORD PTR $FACLO
PUSH WORD PTR $FAC-1 ;FAC PUSHED ON STACK
CALL $FLT ;CONVERT INTEGER TO S.P.
POP BX ;RECALL FAC
POP DX
CALL $FADDS ;ADD IN THE NEW DIGIT
JMP SHORT FI50 ;GET STACK RIGHT AND RETURN
FI35: ;TO GET HERE WE ALREADY HAVE 7 DIGITS AND WOULD
;HAVE A LOSS OF ACCURACY IF WE CONTINUED IN S.P. SO WE
;NEED TO CONVERT TO D.P. MULTIPLY BY 10 AND ADD IN THE DIG.
CALL $CDS ;CONVERT THE SINGLE TO D.P.
FI40: CALL $MUL10 ;MULTIPLY BY 10
CALL $MOVAF ;MOVE $FAC TO $ARG
POP DX ;RECALL DIGIT
CALL $FLT ;CONVERT TO S.P.
CALL $CDS ;CONVERT TO D.P.
CALL $FADDD ;ADD IN THE OLD ACCUMULATED VALUE
FI50: POP CX ;GET DECIMAL POINT FLAG BACK
POP DI ;GET NO. DIGITS TO RIGHT OF DECIMAL PT.
POP BX ;GET TEXT POINTER BACK
RET ;COMPLETE
SUBTTL $FINEX EXPONENT INPUT ROUTINE
;*************************************************************
;
; $FINEX THE PURPOSE OF THIS ROUTINE IS TO DETERMINE
; THE INPUT EXPONENT BASE 10 AND LEAVE IN (DX).
; ADDITIONALLY IF A MINUS "-" SIGN IS ENCOUNTERED
; $FINEX WILL SET ALL BITS OF (SI). OTHERWISE ALL
; BITS OF (SI) WILL BE CLEARED.
; CALLING SEQUENCE: CALL $FINEX
; WITH THE SIGNIFICANT DIGITS OF THE NUMBER IN
; THE FAC.
;
;***************************************************************
$FINEX: LAHF ;SAVE STATUS
CMP BYTE PTR $VALTP,LOW 10 ;SEE IF ALREADY D.P.
JNZ EXA
SAHF ;GET STACK RIGHT
JMP EXB
EXA: SAHF ;RESTORE CODES
PUSH BX ;SAVE IMPORTANT REGISTERS
PUSH DI ;PRECISION ACCORDING TO ZF. IF
CALL $FINFC ;ZF=1 S.P.:ZF=0 THEN D.P.
POP DI ;RECALL DIGITS TO RIGHT OF D.P.
POP BX ;RECALL TEXT POINTER
EXB: XOR SI,SI ;IN CASE EXPONENT IS POSITIVE
MOV DX,SI ;WILL BUILD EXPONENT IN DX
CALL $CHRGT ;GET FIRST CHARACTER OF EXPONENT
JB FX20 ;NO SIGN SO DEFAULT POS.
CMP AL,LOW "-" ;NEGATIVE EXPONENT
JNZ FX00 ;IF NOT MUST BE POSITIVE
NOT SI ;NEGATIVE EXPONENT
JMP SHORT FX10 ;GO GET NEXT CHARACTER
FX00: CMP AL,LOW "+"
JZ FX10
;ILLEGAL CHARACTER MUST LEAVE
RET ;(BX) POINTING HERE
FX10: CALL $CHRGT ;GET NEXT CHARACTER
JB FX20 ;IF DIGIT PROCESS AS EXPONENT
RET ;OTHERWISE RETURN
FX20: CMP DX,3276D ;OVERFLOW IF THIS DOESN'T GET CF=1
JB FX30 ;NO-USE THIS DIGIT
MOV DX,32767D ;TO ASSURE OVERFLOW
JMP SHORT FX10
FX30: PUSH AX ;SAVE NEW DIGIT
MOV AX,10D ;MUST MULTIPLY DX BY 10
MUL DX ;ANSWER NOW IN AX
POP DX ;RECALL DIGIT TO DX
SUB DL,LOW 60 ;SUBTRACT OUT ASCII BIAS
XOR DH,DH ;TO BE SURE AX HAS CORRECT NO.
ADD DX,AX ;ADD TO DX
JMP SHORT FX10
SUBTTL FINFC INPUT FORCE ROUTINES FOR "#","%","!"
;*********************************************************
;
; FINFC THIS MODULE CONTAINS THE ROUTINES $FINI,
; $FIND, AND $FINS FOR FORCING THE INPUT TO
; INTEGER, DOUBLE PRECISION OR SINGLE PRECISION
; RESPECTIVELY IN RESPONSE TO AN INPUT "$","#", OR
; "!". ADDITIONALLY THIS MODULE CONTAINS
; THE UTILITY ROUTINES $FI,$FS,$FD,$CSI,$CSD,$CDS
; FOR FORCING INTEGER,SINGLE,DOUBLE,CONVERTING
; INTEGER TO SINGLE,CONVERTING DOUBLE TO SINGLE, AND
; CONVERTING SINGLE TO DOUBLE, RESPECTIVELY
; CALLING SEQUENCE: CALL $FINI
; OR CALL $FIND
; OR CALL $FINS
; OR CALL $FS
; OR CALL $FD
; OR CALL $FI
; OR CALL $CSI
; OR CALL $CSD
; OR CALL $CDS
; WITH THE FAC CONTAINING THE CURRENT ACCUMULATED
; NUMBER.
;
;***********************************************************
$FIND: ;FORCE INPUT TO DOUBLE PRECISION
OR AL,LOW 1 ;TO SIGNAL DOUBLE PRECISION
$FINS: ;FORCE INPUT TO SINGLE PRECISION (caller has set Z flag)
PUSH BX ;SAVE TEXT POINTER
PUSH DI ;SAVE NO DIGITS AFTER DECIMAL POINT
JNZ FC10 ;Force to double for $FIND callers.
CALL $FS ;Force to single for $FINS callers.
JMP SHORT FC20 ;Skip over $FD call.
FC10: CALL $FD ;FORCE FAC TO DOUBLE PREC.
FC20: POP DI ;RECALL NO DIGITS TO RT. OF DEC PT
POP BX ;RECALL TEXT POINTER
XOR SI,SI ;SINCE THIS IS A FORCED
MOV DX,SI ;NO. EXPONENT IS ZERO
CALL $FINE ;DO IMPLIED EXPONENT FIX-UP
FC30: INC BX ;Point past the force character and
RET ;return.
$FINI: CALL $GETYP ;SET COND CODES ACCORDING TO TYPE
JS FC30
JMP $SNERR ;CAN'T MAKE INTEGER IF NOT ALREADY
$FINFC: JZ $FD ;IF ZF=1 THEN DOUBLE PRECISION
FRCSNG:
$FS: ;FORCE SINGLE PRECISION
CALL $GETYP ;SET COND CODES ACC. TO TYPE
JPO FC200 ;IF ALREADY S.P. RETURN
JNZ FS10
JMP $TMERR ;CAN'T FORCE A STRING
FS10:
JNS $CSD ;IF NOT INTEGER FORCE DOUBLE TO S.P.
CALL $CSI ;FORCE INTEGER TO SINGLE
JMP SHORT FC200
$CSD: ;CONVERT DOUBLE TO SINGLE PRECISION
MOV AL,LOW 4 ;SINGLE PREC DESIGNATION
MOV BYTE PTR $VALTP,AL
MOV BL,BYTE PTR $FAC-1 ;FETCH HIGH MANTISSA BITS
MOV BYTE PTR $FAC+1,BL ;MOVE SIGN TO $FAC+1
MOV DX,WORD PTR $FAC-3 ;FETCH REST OF MANTISSA
MOV AH,BYTE PTR $FAC-4 ;FETCH OVERFLOW BITS
OR AH,LOW 100 ;WANT ROUND-UP IF HIGH BIT SET
OR BL,LOW 200 ;PUT IN UNDERSTOOD 1
JMP $ROUNM ;GO ROUND THE NUMBER
FRCDBL:
$FD: ;FORCE TO DOUBLE PRECISION
CALL $GETYP ;DETERMINE CURRENT TYPE
JNB FC200 ;IF ALREADY DOUBLE EXIT
JNZ FD10
JMP $TMERR
FD10:
JNS $CDS ;IF NOT INTEGER PROCEED
CALL $CSI ;CONVERT INTEGER TO SINGLE PREC.
$CDS: MOV AL,LOW 10 ;DOUBLE PREC. INDICATOR
MOV BYTE PTR $VALTP,AL ;SET TYPE TO D.P.
XOR AX,AX ;MUST ZERO OVERFLOW BYTES
MOV WORD PTR $DFACL,AX
MOV WORD PTR $DFACL+2,AX
RET
$CSI: PUSH DX ;SAVE (DX)
PUSH SI ;SAVE (SI)
MOV DX,WORD PTR $FACLO ;FETCH THE INTEGER
CALL $FLT ;FLOAT THE INTEGER AND STORE IN FAC
POP SI ;GET REGISTERS RIGHT
POP DX
FC200: RET
FRCINT:
$FI: ;FORCE INTEGER
CALL $GETYP ;SEE WHAT WE'RE IN FOR
JNS FI10 ;IF NOT INTEGER ALREADY - JUMP
MOV BX,WORD PTR $FACLO
RET
FI10:
JNZ FFI20
JMP $TMERR ;IF STRING - ERROR
FFI20:
$CINC: ;Single precision, operand in FAC
$CIND: ;Double precision uses same routine
PUSH AX
PUSH CX
MOV AX,WORD PTR $FACM1 ;Get exponent
MOV CX,WORD PTR $FACLO ;Get mantissa
CINT:
XOR BX,BX ;Set up zero result
SUB AH,LOW 200O ;Take bias out of exponent
JB CXRET ;Return zero if no integer part
MOV BH,AL ;Highest byte of mantissa
MOV BL,CH
XCHG AX,CX
MOV CL,LOW 16D
SUB CL,CH ;Number of bits to shift mantissa right
MOV AH,BH ;Save sign
JB OVERFLOW ;If negative shift, it won't fit in 16 bits
JZ OVCHK ;Only -32768 has 16 bits - go check for it
OR BH,LOW 200O ;Set implied bit
SHR BX,CL ;Position the integer
ADC BX,0 ;Perform rounding
JO POSBOVER
OR AH,AH ;Check sign now
JNS CXRET
NEG BX
CXRET:
POP CX
POP AX
MOV WORD PTR $FACLO,BX ;Result in both FAC and BX
VALINT:
$VALNT: MOV BYTE PTR $VALTP,LOW 2
RET
POSBOVER: ;Here for either -32768 or overflow
OR AH,AH ;If signed then -32768
JS CXRET
JMP SHORT OVERFLOW
OVCHK:
;Come here if no shift is needed on the number, i.e., it requires a full
;16 bits. Only -32768 (8000H) is allowed.
CMP BX,100000O ;The 1 is sign bit (negative), not implied bit
JNZ OVERFLOW
TEST AL,LOW 200O ;Should we be rounding up?
JZ CXRET ;If so, that causes overflow
OVERFLOW:
JMP $OVERR
SUBTTL $FLT CONVERT INTEGER IN (DX) TO REAL AND STORE IN FAC
;****************************************************************
; $FLT CONVERTS THE SIGNED INTEGER IN (DX) TO A REAL
; (FLOATING POINT ) NUMBER AND STORES IT IN THE FAC
; AND SETS $VALTP=4
;*****************************************************************
$FLT: XOR BX,BX ;CLEAR HIGH MANTISSA BYTE (BL)
XOR AH,AH ;CLEAR OVERFLOW BYTE
MOV SI,OFFSET $FAC+1 ;FETCH $FAC ADDRESS TO (SI)
MOV BYTE PTR -1[SI],LOW 220 ;SET EXPONENT TO 16
MOV BYTE PTR 0[SI],LOW 0 ;SET SIGN POSITIVE
OR DX,DX ;SETS SF=1 IF NEGATIVE NO.
JNS FLT10 ;IF POSITIVE PROCEED
NEG DX ;NEED POSTIVE MAGNITUDE
MOV BYTE PTR 0[SI],LOW 200 ;SET SIGN TO NEGATIVE
FLT10: MOV BL,DH ;WILL MOVE (DX) TO (BLDH)
MOV DH,DL ;
MOV DL,BH ;SET (DL)=0
MOV BYTE PTR $VALTP,LOW 4 ;SET TYPE TO S.P.
JMP $NORMS ;GO NORMALIZE
SUBTTL $FMULD DOUBLE PRECISION MULTIPLICATION
;**************************************************************
;
; $FMULD THIS ROUTINE FORMS THE DOUBLE PRECISION PRODUCT
; ($FAC):=($FAC)*($ARG)
; THE TECHNIQUE USED IS DESCRIBED IN KNUTH, VOL II
; P.233 AND IS CALLED ALGORITHM "M"
; CALLING SEQUENCE: CALL $FMULD
; WITH THE MULTIPLIER AND MULTIPLICAND IN THE
; $FAC AND $ARG
;
;**************************************************************
DMULT:
$FMULD: ;DOUBLE PRECISION MULT., (FAC)=(FAC)*(ARG)
MOV AL,BYTE PTR $FAC ;WILL FIRST SEE IF FAC IS ZERO
OR AL,AL ;AND IF SO JUST RETURN
JZ FMD10
MOV AL,BYTE PTR $ARG ;WILL NOW SEE IF ARG IS ZERO AND
OR AL,AL ;IF SO SET FAC TO ZERO AND RETURN
JNZ FMD20 ;IF NOT ZERO PROCEED TO MULTIPLY
JMP $DZERO ;ZERO THE FAC
FMD10: RET
FMD20:
MOV BX,WORD PTR $ARG-1 ;FETCH SIGN AND EXP. TO BX
CALL $AEXPS ;ADD THE EXPONENTS
PUSH WORD PTR $FAC ;EXPONENT,SIGN
MOV WORD PTR $ARG-1,BX ;REPLACE UNPACKED MANTISSA
;PUT THE SIGN OF THE PRODUCT IN
;FAC+1
CALL $SETDB ;MOVE THE FAC TO $DBUFF SO PRODUCT
;CAN BE FORMED IN THE FAC, AND ZERO
;THE FAC AND RETURNS WITH (AX)=0
MOV SI,AX ;J
MOV WORD PTR $FAC,AX
MOV BX,OFFSET $DBUFF ;
MOV WORD PTR $ARG,AX
MOV BP,OFFSET $ARGLO ;POINT TO MULTIPLICAND BASE
M1: MOV AX,WORD PTR 0[BX+SI] ;FETCH MULTIPLIER V(J)
OR AX,AX ;SEE IF ZERO
JZ M4D ;IF ZERO W(J)=0
MOV DI,0 ;I
MOV CX,DI ;K
M4: MOV AX,WORD PTR 0[BX+SI] ;FETCH MULTIPLIER V(J)
MUL WORD PTR 0[BP+DI] ;FORM PRODUCT V(J)*U(J) IN (DXAX)
PUSH BX ;SAVE PTR. TO MULTIPLIER BASE
MOV BX,SI ;
ADD BX,DI ;I+J
ADD BX,OFFSET $DFACL-10 ;W(I+J) ADDRESS IN BX
ADD AX,WORD PTR 0[BX] ;(DXAX)=U(I)*V(J)+W(I+J)
JNB M4A
INC DX
M4A: ADD AX,CX ;T=U(I)*V(J)+W(I+J)+K
JNB M4B
INC DX
M4B: MOV WORD PTR 0[BX],AX ;W(I+J)= T MOD 2^16
MOV CX,DX ;K=INT(T/2^16)
POP BX ;RECALL PTR TO MULTIPLIER BASE
CMP DI,6 ;FINISHED INNER LOOP?
JZ M4C ;IF SO JUMP AND SET W(J)
INC DI
INC DI
JMP SHORT M4
M4C: MOV AX,CX ;(AX)=K
M4D: PUSH BX ;SAVE PTR TO MULTIPLIER BASE
MOV BX,OFFSET $DFACL
MOV WORD PTR 0[BX+SI],AX ;W(J)=K OR 0 (0 IF V(J) WERE 0)
POP BX ;RECALL PTR TO MULTIPLIER BASE
CMP SI,6 ;FINISHED OUTER LOOP?
JZ M5
INC SI
INC SI
JMP SHORT M1
M5: ;MULTIPLICATION COMPLETE AND IN FAC
MOV SI,OFFSET $DFACL-2 ;WILL NOW SET ST
STD ;WANT NON-ZERO BYTE ASAP SO PROB.
;SEEMS HIGHER OF GETTING ONE IF
;(SI) IS DECREMENTED
MOV CX,7 ;7-BYTE CHECK
M5AA: LODSB ;FETCH NEXT BYTE
OR AL,AL
LOOPZ M5AA
JZ M5AB ;DON'T NEED TO SET ST
OR BYTE PTR $DFACL-1,LOW 40 ;"OR" IN ST BIT
M5AB:
MOV AL,BYTE PTR $FAC-1 ;SEE IF WE NEED TO INC EXPONENT
OR AL,AL
POP WORD PTR $FAC ;RESTORE EXPONENT,SIGN
JS M6
MOV BX,OFFSET $DFACL-1 ;MUST SHIFT 1 BIT LEFT
MOV CX,4
M5A: RCL WORD PTR 0[BX],1
INC BX
INC BX
LOOP M5A
M5B: JMP $ROUND ;NOW ROUND
M6: INC BYTE PTR $FAC ;INCREMENT EXPONENT
JNZ M5B
JMP $OVFLS ;OVERFLOW!
SUBTTL $FMULS SINGLE PRECISION 8086 MULTIPLICATION
;**********************************************************
; $FMULS FMULS MULTIPLIES THE SINGLE PRECISION
; FLOATING POINT QUANTITIES (BXDX) AND (FAC)
; AND RETURNS THE PRODUCT IN THE (FAC). ONLY
; SEGMENT REGISTERS ARE PRESERVED.
;***********************************************************
$FMULS: ;(FAC)=(BXDX)*(FAC)
CALL $SIGNS ;ZF=1 WILL BE SET IF (FAC)=0
JZ FMS00 ;JUST RETURN IF (FAC)=0
OR BH,BH ;IF EXPONENT OF (BXDX) IS ZERO
JNZ FMS05 ;PROCEED IF NON-ZERO
FMS00: JMP $ZERO ;THE NUMBER IS ZERO.
FMS05:
CALL $AEXPS ;ADD THE S.P. EXPONENTS
;***************************************************************
;WILL NOW PROCEED TO MULTIPLY THE MANTISSAS. THE MULTIPLICATION
;WILL UTILIZE THE 16 BIT MUL INSTRUCTION AND THUS WILL TAKE
;PLACE AS PARTIAL PRODUCTS SINCE WE HAVE 24 BIT MANTISSAS TO
;MULTIPLY.
;***************************************************************
MOV CX,WORD PTR $FAC-1 ;(CH)=($FAC):(CL)=($FAC-1)
XOR CH,CH ;(CX) CONTAINS HIGH MANTISSA BITS
MOV AX,WORD PTR $FAC-3 ;(AX) CONTAINS LOW MANTISSA BITS OF FAC
MOV BH,CH ;SET (BH)=0 AS WELL
;*************************************************************
;AT THIS POINT WE HAVE THE FAC MANTISSA IN (CLAX) AND THE
;(BXDX) MANTISSA IN (BLDX). THE UNDERSTOOD LEADING MANTISSA
;BIT WAS INSTALLED BY $AEXPS AND THE SIGN OF THE PRODUCT
;WAS STORED IN FAC+1
;THE PRODUCT WILL BE FORMED IN (BXCX) BY PARTIAL PRODUCTS.
;FIRST THE NECESSARY ELEMENTS WILL BE PUSHED ON THE STACK
;THEN UTILIZED IN REVERSE ORDER(THAT'S THE BEST WAY TO
;GET THE THEM OFF THE LIFO STACK -TURKEY!)
;************************************************************
MOV SI,BX
MOV DI,CX
MOV BP,DX
PUSH CX ;HIGH FAC MANTISSA BITS
PUSH AX ;LOW FAC MANTISSA BITS
MUL DX ;32 BIT PRODUCT FORMED(ONLY NEED
MOV CX,DX ;MOST 16 SIGNIFICANT BITS)
POP AX ;LOW FAC MANTISSA BITS
MUL BX ;TIMES HIGH MANTISSA BITS OF (BLDX)
ADD CX,AX ;ADD TO PREVIOUS CALCULATION
JNB FMS10 ;IF CARRY NOT PRODUCED PROCEED
INC DX
FMS10: MOV BX,DX ;PROBABLY ONLY 8 BITS HERE
POP DX ;HIGH FAC MANTISSA BITS
MOV AX,BP ;LOW 16 MANTISSA BITS OF (BLDX)
MUL DX ;
ADD CX,AX ;ADD IN LOW ORDER BITS
JNB FMS20 ;JUMP IF CARRY NOT PRODUCED
INC DX ;
FMS20: ADD BX,DX ;CAN'T PRODUCE CARRY HERE
MOV DX,DI ;HIGH FAC MANTISSA BITS
MOV AX,SI ;HIGH FAC MANTISSA BITS
MUL DL ;(AX) HAS ENTIRE PRODUCT
ADD BX,AX ;ADD IT IN
JNB FMS30 ;IF NO CARRY PROCEED
RCR BX,1 ;MOVE EVERYTHING RIGHT
RCR CX,1 ;
INC BYTE PTR $FAC ;MUST NOW CHECK FOR OVERFLOW
JNZ FMS30 ;PROCEED IF NON-ZERO
JMP $OVFLS
FMS30: ;PRODUCT FORMED, MUST NOW GET MANTISSA IN (BLDXAH) FOR ROUNS
;PRODUCT IS CURRENTLY IN (BXCX)
OR BH,BH ;MUST BE SURE PRODUCT LEFT JUSTIFIED
JNS FMS35 ;IN (BXCX)
INC BYTE PTR $FAC ;NEED TO INCREMENT EXP.
JNZ FMS37 ;IF NOT OVERFLOW PROCEED
JMP $OVFLS ;OVERFLOW JUMP
FMS35:
RCL CX,1
RCL BX,1
FMS37:
MOV DL,CH
MOV DH,BL
MOV BL,BH
MOV AH,CL ;OVERFLOW BYTE
JMP $ROUNS ;GO ROUND
RET
SUBTTL $FOTAN ROUTINE TO PUT IN DECIMAL POINT AND LEADING ZEROS
;*****************************************************************
;
; $FOTAN THIS ROUTINE IS CALLED BY THE FREE FORMAT OUTPUT
; CODE TO OUTPUT DECIMAL POINT AND LEADING ZEROS.
; $FOTED THIS ROUTINE IS CALLED BY BOTH THE FREE FORMAT
; OUTPUT ROUTINE AND THE PRINT USING CODE TO OUTPUT
; THE DECIMAL POINT WHEN NECESSARY AND TO PUT IN
; COMMAS "," AFTER EACH THREE DIGITS IF THIS OPTION
; IS INVOKED.
; CALLING SEQUENCE: CALL $FOTAN
; CALL $FOTED
; WITH $FMTCX CONTAINING NUMBER PLACES PRIOR TO
; DECIMAL POINT(NEGATIVELY) IN UPPER BYTE AND
; NO PLACES BEFORE NEXT COMMA IN LOW BYTE
;
;*******************************************************************
$FOTAN:
DEC CH ;IF NEGATIVE THEN LEADING ZEROS
JNS FTD05 ;
MOV WORD PTR $DPADR,BX ;SAVE DECIMAL POINT COUNT
MOV BYTE PTR 0[BX],LOW "." ;MOVE IN DECIMAL POINT
FTN10: INC BX ;POINT TO NEXT OUTPUT POSITION
MOV BYTE PTR 0[BX],LOW "0" ;PUT IN LEADING ZERO
INC CH ;WILL INCREMENT CH UNTIL ZERO
JNZ FTN10 ;PUT IN LEADING ZEROS UNTIL CH ZERO
INC BX ;POINT TO NEXT BUFFER POSITION
XOR CX,CX ;ZERO OUT DECIMAL POINT AND COMMA CTS.
JMP SHORT FTD20 ;GET STACK RIGHT AND RETURN
$FOTED:
DEC CH ;SEE IF TIME FOR D.P.
FTD05: JNZ FTD10 ;IF NOT D.P. TIME SEE IF COMMA TIME
MOV BYTE PTR 0[BX],LOW "." ;PUT IN D.P.
MOV WORD PTR $DPADR,BX ;SAVE ADDR OF DECIMAL POINT
INC BX ;INCREMENT PAST D.P.
XOR CX,CX ;ZERO COUNTS & SET ZF=1
JMP SHORT FTD20 ;GET STACK RIGHT AND RETURN
FTD10: DEC CL ;IF ZERO TIME FOR COMMA
JNZ FTD20
MOV BYTE PTR 0[BX],LOW 54O ;COMMA
INC BX ;POINT TO NEXT BUFFER POSITION
MOV CL,LOW 3 ;
FTD20: MOV WORD PTR $FMTCX,CX ;UPDATE D.P.&COMMA COUNTS
RET
SUBTTL $FOTCV CONVERT FAC TO ASCII DIGITS
;************************************************************
;
; $FOTCV CONVERSION OF SINGLE OR DOUBLE PRECISION
; NUMBER TO ASCII DIGITS.IF DOUBLE PRECISION
; 10 DIGITS WILL BE CONVERTED WITH DOUBLE
; PRECISION POWER OF TEN INTEGERS, 3 DIGITS
; WITH SINGLE PRECISION POWER OF TEN INTEGERS
; AND 3 DIGITS WITH INTEGER POWERS OF TEN
; CALLING SEQUENCE: CALL $FOTCV
; WITH THE NUMBER TO BE CONVERTED HAVING PREVIOUSLY
; BEEN OPERATED ON BY $FOTNV TO BRACKET THE
; NUMBER AND HAVE ALL DIGITS IN THE INTEGER PORTION
; OF THE FAC. AND THE CORRESPONDING EXPONENT WILL
; BE SAVED ON THE STACK AND CONVERTED LATER.
;
;**************************************************************
$FOTCV: CALL $GETYP ;SET CONDITION CODES FOR VALTYP
JPO FCV40 ;IF SINGLE PRECISION GO PROCESS
PUSH CX ;SAVE DIGIT AND COMMA COUNT
PUSH BX ;SAVE BUFFR PTR.
MOV SI,OFFSET $DFACL ;WILL MOVE FAC TO ARG
MOV DI,OFFSET $ARGLO
MOV CX,4
CLD
REP MOVSW
CALL $DINT ;WILL SEE IF FAC ALREADY INTEGER
PUSH BX ;NEED TO CALL VCOMP WITH BX=ARG-1
MOV BX,OFFSET $ARG-1
CALL $VCOMP ;DO COMPARE
POP BX ;GET BUFFER POINTER BACK
MOV SI,OFFSET $ARGLO ;WILL MOVIE ARG TO FAC
MOV DI,OFFSET $DFACL
MOV CX,4
CLD
REP MOVSW
JZ FCV05 ;DON'T ADD .5 IF NO DIFF.
CALL $DADDH ;ADD .5 TO NUMBER
FCV05: MOV CL,BYTE PTR $FAC ;SHIFT COUNT IN (CL)
SUB CL,LOW 270
NEG CL ;MAKE SHIFT COUNT POSITIVE
CLC ;TO TELL DINT NOT TO NORMALIZE
CALL $FTDNT ;MAKE SURE ITS STILL INTEGER
POP BX ;RECALL BUFFER PTR.
POP CX ;RECALL DIGIT AND COMMA COUNT
MOV SI,OFFSET $FODTB ;DOUBLE PRECISION OUTPUT INTEGERS
MOV AL,LOW 9D ;9 DIGITS TO BE CONVERTED WITH D.P.
FCV10: CALL $FOTED ;SEE IF DECIMAL POINT NEEDED
PUSH AX ;SAVE DIGIT COUNT
MOV AL,LOW OFFSET "0"-1 ;WILL FORM DIGIT IN (AL)
PUSH AX
FCV20: POP AX ;RECALL DIGIT
INC AL ;INCREMENT TO NEXT DIGIT
PUSH AX ;SAVE DIGIT
CALL DSUBI ;SUBTRACT POWER OF TEN
JNB FCV20
CALL DADDI ;ADD POWER 10 BACK IN
;AND ADVANCE SI TO NEXT POWER 10
POP AX ;GET DIGIT BACK
MOV BYTE PTR 0[BX],AL ;PUT IN ASCII DIGIT
INC BX ;POINT TO NEXT BUFFER POSITION
POP AX ;GET DIGIT COUNT
DEC AL ;SEE IF 10 DIGITS FORMED
JNZ FCV10 ;IF NOT CONTINUE THE ALGORITHM
PUSH CX ;SAVE DECIMAL POINT COUNT
MOV SI,OFFSET $DFACL ;WILL MOVE INTO FAC
MOV DI,OFFSET $FACLO
MOV CX,2
CLD
REP MOVSW
POP CX ;RECALL DECIMAL POINT COUNT
JMP SHORT FCV50 ;GO DO THE REST OF THE DIGITS
FCV40:
;**************************************************************
;CODE BELOW WORKS WITH SINGLE PRECISION NUMBERS
;***************************************************************
PUSH BX ;SAVE BUFFER PTR
PUSH CX ;SAVE DIGIT AND COMMA COUNTS
CALL $PUSHF ;SAVE $FAC ON STACK
CALL $INT ;WILL SEE IF INTEGER CURRENTLY
POP DX ;RECALL FAC
POP BX
CALL $FCOMP ;COMPARE IF EQUAL DON'T ADD .5
JZ FCV45
MOV WORD PTR $FAC-1,BX ;MOVE BACK TO FAC
MOV WORD PTR $FACLO,DX
CALL $FADDH ;ADD .5 TO NUMBER
FCV45: MOV AL,LOW 1 ;FLAG TO QINT WE HAVE A POS. NO.
CALL $QINT ;GET INTEGER INTO (BLDX)
MOV WORD PTR $FAC-1,BX
MOV WORD PTR $FACLO,DX ;MOVE TO FAC
POP CX ;RECALL DIGIT AND COMMA COUNTS
POP BX ;RECALL BUFFER PTR
FCV50:
MOV AL,LOW 3 ;WILL CONVERT 3 DIGITS IN THIS CODE
MOV DX,OFFSET $FOSTB ;Print S.P. numbers with 7 digits
FCV60: CALL $FOTED ;SEE IF NEED A DECIMAL POINT OR COMMA
PUSH AX ;SAVE DIGIT COUNT
PUSH BX ;SAVE BUFFER POINTER
PUSH DX ;SAVE POWER OF TEN POINTER
CALL $MOVRF ;FETCH INTEGER
POP BP ;FETCH POWER TEN POINTER
MOV AL,LOW OFFSET "0"-1 ;WILL BUILD DIGIT IN (AL)
PUSH AX ;SAVE DIGIT
FCV70: POP AX ;RECALL DIGIT
INC AL ;GO TO NEXT DIGIT
PUSH AX
CALL $RSUBM ;SUBTRACT NO. POINTED TO BY (BP)
;FROM (BLDX)
JNB FCV70 ;CONTINUE UNTIL CF=1
;POWER TEN TABLE IN CODE SEGMENT
ADD DX,WORD PTR CS:0[BP] ;ADD WORD PORTION
ADC BL,BYTE PTR CS:2[BP]
;SINCE WE SUBTRACTED ONE TOO MANY
INC BP ;INCREMENT TO NEXT POWER OF TEN
INC BP
INC BP
CALL $MOVFR ;SAVE (BLDX) IN FAC
POP AX ;RECALL DIGIT
XCHG DX,BP ;SAVE POWER TEN PTR. IN DX
POP BX ;RECALL BUFFER POINTER
MOV BYTE PTR 0[BX],AL ;SEND OUT DIGIT
INC BX ;INCREMENT TO NEXT BUFFER POSITION
POP AX ;RECALL DIGIT COUNT
DEC AL ;SEE IF FINISHED
JNZ FCV60 ;IF NOT CONTINUE
INC DX ;NEED TO INCREMENT PAST 1ST
INC DX ;INTEGER SO THAT FOTCI WILL
MOV BP,DX ;FOTCI IS EXPECTING POINTER IN BP
MOV AH,LOW 4 ;CONVERT ONLY 4 DIGITS
JMP $FCI4
;INTEGER ARITHMETIC
DSUBI: ;SUBTRACT 7 BYTE INTEGER POINTED TO BY (SI) FROM $DFACL
PUSH CX ;FIRST SAVE CX,SI,DI
PUSH SI
MOV CX,7 ;7 BYTES
MOV DI,OFFSET $DFACL
CLC ;CF=0
CLD ;SO LODC WILL INCREMENT
DSUBI1: ;NEED NO. FROM CODE SEGMENT
LODS BYTE PTR ?CSLAB ;FETCH BYTE TO AL
SBB BYTE PTR 0[DI],AL ;SUBTRACT
INC DI
LOOP DSUBI1
POP SI
POP CX
RET
DADDI: ;ADD 7 BYTE INTEGER POINTED TO BY (SI) FROM $DFACL
PUSH CX ;SAVE CX,SI,DI
MOV CX,7
MOV DI,OFFSET $DFACL
CLC
CLD ;SO LODC WILL INCREMENT SI
DADDI1: ;WANT NO. FETCHED FROM CODE SEGMENT
LODS BYTE PTR ?CSLAB ;FETCH NEXT BYTE TO ADD
ADC BYTE PTR 0[DI],AL ;ADD IT IN
INC DI
LOOP DADDI1
POP CX
RET
SUBTTL $FOTNV BRACKET FAC SO PRINTABLE DIGITS IN INTEGER PART
;****************************************************************
;
; $FOTNV THIS ROUTINE MULTIPLIES THE FAC BY APPROPRIATE
; VALUES SO THAT THE PRINTABLE DIGITS (7 FOR SINGLE
; PRECISION, 16 FOR DOUBLE PRECISION) ARE IN THE
; INTEGER PART OF THE FAC . IT RETURNS THE COMPLEMENT-
; ING EXPONENT IN (AL).
; CALLING SEQUENCE: CALL $FOTNV
; WITH THE FAC CONTAINING THE DESIRED VALUE TO PRINT
; REGISTERS (BX) AND (CX) WILL RETAIN THEIR VALUES
;
;*****************************************************************
$FOTNV:
PUSH BX ;WON'T ALTER (BX) OR (CX)
PUSH CX
XOR DI,DI ;INITIALIZE EXPONENT
PUSH DI ;SAVE EXPONENT
FNV10: MOV BX,OFFSET $FOTB ;ADDRESS OF BRACKET CONTROL TABLE
MOV AL,BYTE PTR $FAC ;FETCH THE EXPONENT
;MUST FETCH FROM CODE SEGMENT
XLAT BYTE PTR ?CSLAB ;GET MULTIPLIER
OR AL,AL ;IF ZERO - DONE
JZ FNV20
POP DI ;RECALL EXPONENT
CBW ;CONVERT AL TO WORD
SUB DI,AX ;GET EXPONENT CORRECT
PUSH DI ;SAVE EXPONENT
MOV DX,AX ;DX:=exponent for MDPTEN.
CALL MDPTEN ;Multiply or divide by power of ten.
JMP SHORT FNV10 ;See if need to do it again.
FNV20: MOV BX,OFFSET $DP06+4 ;LOWER BOUND
CALL $MOVBS ;MOVE OUT TO "DS" AREA
CALL $COMPM ;ONE MORE MULT. POSSIBLE
;$COMPM WILL SET CF=1 IF $DP06
;IS LARGER, CF=0 FOR EQ OR GT
JNB FNV30 ;JUMP IF NOT NEEDED
CALL $MUL10 ;MULTIPLY BY TEN
POP DI ;RECALL EXPONENT
DEC DI ;ACCOUNT FOR MULTIPLY BY 10.
PUSH DI
FNV30: CALL $GETYP ;SET CONDITION CODES FOR TYPE
JB FNV40 ;done if single precision
MOV BX,OFFSET $DP09 ;MUST MULTIPLY BY 10^9
CALL $MOVAC ;MOVE 10^9 TO $ARG
CALL $FMULD ;PERFORM MULTIPLICATION
POP AX ;RECALL EXPONENT
SUB AL,LOW 11 ;SUBTRACT 9
PUSH AX ;Resave the exponent.
MOV BX,OFFSET HIDBL ;Is the number too big? (Will it
CALL $MOVBF ;overflow when $FOTCV adds .5 to it?)
CALL $DCMPM
JNA FNV40 ;No.
FNV44: CALL $DIV10 ;Yes, divide by ten and fix up the
;the decimal exponent.
POP AX ;restore the exponent
INC AL ;adjust for $DIV10
PUSH AX
FNV40: POP AX ;recall exponent
FNV50: POP CX ;restore registers
POP BX
OR AL,AL ;SET CONDITION CODES ACCORDING TO EXP
RET
;
; The largest double precision value that .5 can be added to without
; overflow occuring.
;
HIDBL: DB 375,377,3,277,311,33,16,266 ;9999999999999999.
SUBTTL $FOUT CONTROL OUTPUT CONVERSION
;***************************************************************
;
; $FOUT THIS ROUTINE PROVIDES TOP-LEVEL CONTROL OF THE
; FREE FORMAT OUTPUT FUNCTION.
; CALLING SEQUENCE: CALL $FOUT
;
;****************************************************************
S: MOV BX,OFFSET $FBUFF+1 ;FETCH BUFFER POINTER
MOV BYTE PTR 0[BX],LOW " " ;MOVE IN SPACE FOR POSSIBLE SIGN
PUSH BX ;SAVE BUFFER POINTER
CALL $SIGNS ;DETERMINE SIGN OF NUMBER
POP BX ;RECALL BUFFER POINTER
PUSHF ;SAVE FLAGS FOR LATER
JNS FO20 ;JUMP IF POSITIVE
MOV BYTE PTR 0[BX],LOW "-" ;PUT IN MINUS SGN
PUSH BX ;SAVE TEXT POINTER
CALL $VNEG ;NEGATE NO. SO WE WORK ONLY WITH
POP BX ;RECALL TEXT POINTER
OR AL,LOW 1 ;POS. NOS. AND SET ZF=0
FO20: INC BX ;POINT TO NEXT BUFFER POSITION
MOV BYTE PTR 0[BX],LOW "0" ;PUT IN ZERO IN CASE NO IS ZERO
POPF ;RECALL FLAGS
RET
FOUT:
$FOUT: ;FREE-FORMAT ENTRY POINT
CALL S ;DO SIGN FIX-UP
JNZ $FOUT2 ;IF NON-ZERO PROCEED
INC BX ;POINT TO NEXT OUTPUT BUFFER POS.
MOV BYTE PTR 0[BX],LOW 0 ;INDICATE END OF NUMBER
MOV BX,OFFSET $FBUFF+1 ;POINT (BX) TO START POSITION
RET
$FOUT2: CALL $GETYP ;GET TYPE NO.
JNS FO50 ;GO FORMAT SINGLE OR DOUBLE PREC.
MOV CX,OFFSET 7*400 ;default 7 digits prior to dp.
XOR AX,AX ;CLEAR COMMA COUNT
MOV WORD PTR $FMTAX,AX
MOV WORD PTR $FMTCX,CX
CALL $FOTCI ;CONVERT INTEGER TO ASCII
JMP $FOTZS ;DO LEADING ZERO SUPPRESSION
FO50: JMP $FOFMT ;SINGLE OR DOUBLE PREC. OUTPUT
SUBTTL $INT CONVERT PRESENT NO. TO INTEGER BY TRUNCATION
;***********************************************************
;
; $INT SINGLE PRECISION INT ROUTINE
; $DINT DOUBLE PRECISION INT ROUTINE
; $QINT CONVERT TO INT AND LEAVE IN (BLDX)
; $FTDNT FOUT ENTRY TO CONVERT TO INT AND LEAVE RT.ADJUSTED
; $SHRD SHIFT DOUBLE PRECISION MANTISSA RIGHT
;
;**********************************************************
;**********************************************************
;THE INT TECHNIQUE IS PRETTY STRAIGHT FORWARD EXCEPT
;FOR NEGATIVE NON-INTEGERS. THE RUB WITH THESE NOS. IS THAT
;IF THEY HAVE ANY FRACTIONAL BITS THE ANSWER IS TO
;BE THE NEXT LOWER VALUE INTEGER. FOR EXAMPLE : INT(-1.1) SHOULD
;RETURN -2 WHEREAS INT(1.1) SHOULD RETURN 1. THE TRICK USED TO
;EFFECT THIS IS TO SUBTRACT 1 FROM NEGATIVE NON-INTEGER MANTISSAS
;PRIOR TO SHIFTING OUT FRACTIONAL BITS THEN ADD 1 BACK TO THE
;MANTISSA ONCE FRACTIONAL BITS HAVE BEEN SHIFTED OUT. WITH THE
;FOLLOWING EXAMPLE (IN BINARY) WATCH HOW THIS TECHNIQUE WORKS:
;FIND INT(10011.011)
; (1) SINCE THIS IS A POSITIVE NO WE JUST SHIFT OUT
; THE FRACTIONAL BITS AND NORMALIZE
;FIND INT(-10011.011)
; (1) SUBTRACT ONE FROM THE MANTISSA YIELDING -10011.010
; (2) SHIFT OUT THE FRACTIONAL BITS YIELDING -10011.
; (3) ADD 1 TO MANTISSA YIELDING -10100 THE CORRECT VALUE
;FIND INT(-10011.000)
; (1) SUBTRACT ONE FROM MANTISSA YIELDING -10010.111
; (2) SHIFT OUT THE FRACTIONAL BITS YIELDING -10010.
; (3) ADD 1 TO MANTISSA YIELDING -10011. THE CORRECT VALUE
;******************************************************************
$DINT: ;DOUBLE PRECISION INT FUNCTION
MOV CL,BYTE PTR $FAC ;CL:=exponent.
SUB CL,LOW 270 ;Is there a fractional part?
JNB DNT20 ;RETURN IF NO FRACTIONAL BITS
NEG CL ;CL NOW POSITIVE
$FTDNT: PUSHF ;FOUT ENTRY POINT. THIS IS SEPARATE
;ENTRY POINT BECAUSE FOUT WISHES
;TO HAVE INTEGER RIGHT ADJUSTED
;IN THE MANTISSA BITS. WE WILL DO
;THE NECESSARY SHIFTS AND RETURN
;PRIOR TO NORMALIZATION IF CALLED
;BY FOUT (SIGNIFIED BY CF=0)
TEST BYTE PTR $FAC,LOW 377O ;Is the exponent zero?
JNE DINTNZ ;No, proceed.
POPF ;Yes, if the exponent is zero the
RET ;number is zero. Don't operate on
;the possible garbage in the mantissa.
DINTNZ: MOV BX,OFFSET $FAC-2
MOV AL,BYTE PTR 1[BX] ;FETCH SIGN BYTE
MOV BYTE PTR 3[BX],AL ;AND PUT IN $FAC+1 FOR $NORMD
OR AL,AL ;SEE IF NEGATIVE
PUSHF
OR AL,LOW 200 ;RESTORE HIDDEN 1
MOV BYTE PTR 1[BX],AL ;AND REPLACE
MOV BYTE PTR 2[BX],LOW 270 ;SET EXPONENT FOR POST SHIFT VALUE
POPF ;RECALL SF
PUSHF
JNS DNT10 ;IF POSITIVE PROCEED
;*****************************************************************
;NEGATIVE NO. MUST DO THE FANCY FOOTWORK DESCRIBED ABOVE
;*****************************************************************
CALL DINTA ;SUBTRACT 1 FROM MANTISSA BITS
DNT10: XOR CH,CH ;(CX)=SHIFT COUNT
CALL $SHRD ;DOUBLE PRECISION SHIFT RIGHT
POPF ;RECALL SF
JNS DNT15 ;IF POSITIVE PROCEED
CALL ADD1D ;ADD 1 TO MANTISSA BITS
DNT15: MOV BYTE PTR $DFACL-1,LOW 0 ;ZERO THE OVERFLOW BYTE
POPF ;SEE IF CALLED BY FOUT (CF=0)
JNB DNT20 ;IF SO JUST RETURN
JMP $NORMD ;OTHERWISE NORMALIZE
DNT20: RET
$SHRD: ;SHIFT RIGHT DOUBLE PRECISION
SHRD10: PUSH CX ;SAVE OUTER LOOP VARIABLE (BITS TO
;BE SHIFTED RIGHT)
PUSH BX ;SAVE POINTER TO HIGH BYTE TO SHIFT
CLC ;CF=0
CALL $SHDR ;SHIFT 1 BIT RIGHT
POP BX
POP CX ;GET OUTER LOOP VARIABLE
LOOP SHRD10
RET
DINTA: PUSH BX
MOV BX,OFFSET $DFACL ;BEGINNING ADDRESS FOR SUBTRACT
DINA10: SUB WORD PTR 0[BX],1 ;NEED CF SO CAN'T USE DEC
JNB DINA20
INC BX
INC BX ;CAN DO WORD SUBTRACTS SINCE HIGH BIT
;OF MANTISSA IS SET (THUS PROTECTING
;THE EXPONENT FROM THE SUBTRACT)
JMP SHORT DINA10
DINA20: POP BX
RET
ADD1D: ;ADD 1 TO DOUBLE PRECISION MANTISSA BITS
PUSH BX ;
MOV BX,OFFSET $DFACL
ADD10: INC BYTE PTR 0[BX]
JNZ ADD20
INC BX ;POINT TO NEXT BYTE THERE WAS A CARRY
JMP SHORT ADD10
ADD20: POP BX
RET
INT:
$INT: ;SINGLE PRECISION INT FUNCTION
MOV CL,BYTE PTR $FAC ;FETCH EXPONENT
SUB CL,LOW 230 ;CALCULATE SHIFT COUNT
JNB INT20 ;ALREADY INTEGER PROCEED
NEG CL ;GET POSITIVE SHIFT COUNT
;
; Note - At this point the carry is set. This will be used
; to indicate that this is not a QINT call. Also note that
; if the exponent is zero the above subtraction did set the
; carry so the check for the zero exponent case below is
; guaranteed to be executed.
;
QINTX: ; $QINTX'S ENTRY POINT
MOV DX,WORD PTR $FACLO ;FETCH LOW MANTISSA BITS
MOV BX,WORD PTR $FAC-1 ;FETCH EXP,SIGN,HIGH MANTISSA BITS
INC BH ;Is the exponent zero? (Test for zero
DEC BH ;without affecting the carry.)
JNE QINTNZ ;No, proceed.
XOR BL,BL ;Yes, put zero into BL,DX for QINT
XOR DX,DX ;rather than work with the possible
RET ;garbage in the mantissa (an exponent
;of zero means the number is zero).
QINTNZ: PUSHF ;Save carry which if clear indicates
;this is a QINT call.
OR BL,BL ;SEE IF NEGATIVE
PUSHF ;SAVE
MOV BYTE PTR $FAC+1,BL ;SAVE SIGN FOR NORMS
MOV BYTE PTR $FAC,LOW 230 ;SET EXP FOR POST SHIFT
OR BL,LOW 200 ;RESTORE HIDDEN 1
POPF
PUSHF ;SAVE SIGN
JNS INT10 ;
SUB DX,1 ;CAN'T DO A 'DEC' BECAUSE NEED CF
SBB BL,LOW 0 ;DO APPROPRIATE SUBTRACT TO HIGH BYTE
INT10: XOR CH,CH ;CX HAS LOOP COUNT
OR CL,CL ;IF SHIFT COUNT ZERO MUST JUMP OVER
JZ INT12 ;RIGHT SHIFTS
INT11: SHR BL,1 ;SHIFT RIGHT INTO CF
RCR DX,1 ;ROTATE RIGHT
LOOP INT11 ;WILL DO (CX) RIGHT SHIFTS
INT12: POPF ;RECALL SIGN OF NO.
LAHF ;STORE FLAGS TEMPORARILY
JNS INT15 ;PROCEED IF POSITIVE
INC DX
JNZ INT15
INC BL
INT15:
POPF ;CF=0 IF CALLED BY QINT
JNB INT20 ;JUST RETURN IF QINT CALL
XOR AH,AH ;CLEAR OVERFLOW BYTE
JMP $NORMS ;NORMALIZE AND RETURN
INT20: SAHF ;MUST SEE IF NEGATIVE
NGBLDX: JNS INT30 ;IF NOT PROCEED AS NORMAL
NOT DX ;COMPLEMENT DX
NOT BL ;AND BL
ADD DX,1 ;NEED CF SET IF DX OVERFLOWS
ADC BL,LOW 0 ;2's COMPLEMENT NOW FORMED
INT30: RET
QINT:
$QINT: ;DO INT(FAC) AND LEAVE IN (BLDX)
MOV CL,LOW 230
SUB CL,BYTE PTR $FAC ;GET SHIFT COUNT TO CL
CLC ;CF=0
JMP SHORT QINTX ;LEAVE RIGHT ADJUSTED
SUBTTL $LOG SINGLE PRECISION NATURAL LOG FUNCTION
;**********************************************************
;