This repository was archived by the owner on Oct 3, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathreal_math.inc
5302 lines (4982 loc) · 181 KB
/
real_math.inc
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
; MREAL macros, by qWord, 2014
; Version 1.0.4
; This file is best viewed with a fixed-width font and a tab size of 4.
;
; Overview
; The MREAL macros allows arbitrary** precision floating point arithmetic while assembling. The values are stored
; in a collection of equates, following a strict naming pattern. For the further documentation this equates are called
; "MREAL value" or "MREAL variable".
; The goal of the macros is to implement a subset of the IEEE 754-2008 standard.
; (** multiples of 16 bit: 16,32,48,...)
;
; Currently the following features are implemented:
; - correctly rounded arithmetic: addition, subtraction, multiplication, division, square root and fused multiply accumulate.
; - rounding modes: round to nearest ties to even and ties away from zero, round toward +Infinity (=round up),
; round toward -Infinity (=round down) and round toward zero (=truncate).
;
; The most important difference to IEEE 754 are:
; - precision: multiplies of 16: 16, 32, 48, 64, ... bit
; (However, single and double precision could be simulated if needed)
; - denormal numbers are not supported
; - there is no negative zero (-0) **
; - propagation of special values: +-Infinity as input
; always produce NaN as result. **
;
; ** This might be implemented in future versions as required by IEEE754-2008.
;
;
; Internal representation of MREAL values
;
; equate | type | description
; ------------------------+-----------+-------------------------------------------------------------------------------------
; MREAL_&name&_exp | Integer | exponent
; MREAL_&name&_w0...(N-1) | WORD | unsigned mantissa bits, starting with the most significant WORD. N = MREAL_XDIM
; | | The mantissa is normalized to 2^(-1) = 0.5, which is the MSB and is always present.
; | | The LSB is 2^(-MREAL_XDIM*16). Denormal numbers are not supported.
; | | Only the low words of the equates are used by the macros, but it is expected that
; | | the high words are zero - nonzero high words cause unpredictable behavior!
; | |
; MREAL_&name&_flg | DWORD | flags:
; | | value | description | combinable?
; | | ----------+--------------+---------------
; | | 00000001h | Zero | no
; | | 00000002h | Infinity | with Sign
; | | 00000004h | NaN | no
; | | 80000000h | Sign | with Infinity
; | | others | reserved=0 |
; | |
; | | For the flags "zero", "Infinity" and "NaN" the exponent and mantissa are ignored.
; | |
;
; Internally used constants may have two additional equates:
;
; equate | type | description
; ------------------------+-----------+--------------------------------------------------------------------------
; MREAL_&name&_n | DWORD | number of mantissa WORDs.
; MREAL_&name&_nSig | DWORD | number of nonzero mantissa WORDs, starting with the most significant WORD.
;
; Examples:
; The following examples assumes that MREAL_XDIM = 1, means 16 bit precision. The MREAL name\ID is "X".
; value = +1.0 :
; MREAL_X_flg = 0
; MREAL_X_exp = 1
; MREAL_X_w0 = 8000h
; ==> +(0.5)*2^1 == 0.5*2 == 1.0
; value = -3.0 :
; MREAL_X_flg = 80000000h
; MREAL_X_exp = 2
; MREAL_X_w0 = 0C000h
; ==> -(0.75)*2^2 == -0.75*4 == -3.0
; value = 0.0 :
; MREAL_X_flg = 1
; MREAL_X_exp = arbitrary value
; MREAL_X_w0 = arbitrary value
;
; Rounding modes
; The macros support 5 different rounding modes:
; round:
; - to nearest with tie-breaking rules:
; - ties to even (round half to even, IEEE754 default for binary formats)
; - ties away from zero (round half away from zero, actual IEEE754-2008 requires this mode only for decimal formats)
; - toward -Infinity (down)
; - toward +Infinity (up)
; - toward zero (truncate)
;
; The default rounding mode is "round to nearest, ties to even".
;
; Under- and Overflow
; Exponent Over- and Underflow are detected after
; the actual operation. In such cases the result is rounded
; according to IEEE754-2008.
;
; Detecting inexact operations
; If the global equate MREAL_TEST_INEXACT is nonzero, all arithmetic, rounding and conversion
; operations does set the equate MREAL_INEXACT to -1 if the result is not exact representable
; in the current number format (precision and exponent setting).
; By default the test is disabled (MREAL_TEST_INEXACT=0).
;
; Important notes on the macros
; - the result parameter can also be an input parameter
; - IDs/names of MREAL values must not have leading or trailing white spaces.
; - MREAL values are implicit created for result parameters!
; - generally, do not pass unprocessed/unevaluated expression to the macros,
; especially for numeric parameters -> use MASM's expansion operator % if needed.
; - remarks that MREAL IDs/names reside in their own name space due to the internal representation of MREAL values.
; This means they can have (for example) the same name as local or global variables.
; - Names beginning with a question mark followed by one lower-case character (a-z, e.g. "?q") might be internally
; used by the MREAL macros. Furthermore some macros use names of the form "xTmp", whereas x is a shortcut
; of the macro name in lower case.
;
; End user macros
; [r, x, y, a, b, c denotes MREAL values. The value for TRUE is -1, FALSE is 0. |x| is the
; absolute value of x. round(x) rounds x to an integer in current rounding mode. pwr2, N and "value" are
; MASM integer expression. "^" means exponentiation]
;
; Procedures:
; MR_ADD r,x,y -> r = x+y
; MR_SUB r,x,y -> r = x-y
; MR_MUL r,x,y -> r = x*y
; MR_DIV r,x,y -> r = x/y
; MR_SQRT r,x -> r = x^(1/2)
; MR_FMADD r,a,b,c -> r = a*b + c
; MR_FMSUB r,a,b,c -> r = a*b - c
; MR_FNMADD r,a,b,c -> r = -a*b + c
; MR_FNMSUB r,a,b,c -> r = -a*b - c
; MR_MOV r,x -> r = x
; MR_SET_ZERO r -> r = 0
; MR_CREATE r -> r = 0
; MR_ROUND r,x,pwr2 -> r = round(x*2^(-pwr2))*2^pwr2
; MR_DEF_REAL10 lbl,x -> define REAL10 variable/constant in current segment, initialized with value x.
; This macro is a bug fix for MASM v6-7.
; MR_CONVERT r,x,nx,nr -> convert x to r. nx and nr specifies the number of precision WORDs.
; MR_ABS r,x -> r = |x|
; MR_NEG r,x -> r = -x
; MR_COPY_SIGN r,x,y -> r = sgn(y)*|x|
; MR_CMP x,y -> compare x with y and store the result in the equate mr_cmp.
; mr_cmp = -2 -> unordered (x or/and y are NaN)
; -1 -> x < y
; 0 -> x == y
; 1 -> x > y
; This macro allows to compare infinite values.
; MR_FROM_EXPR32 r,value -> convert the numeric expression "value" (MASM expression, 32 bit) to MREAL r.
; MR_XMUL r,x,y,nr,nx,ny -> r=x*y, multiplication with operands of different precision. Remarks that 1 <= nr <= nx+ny.
; MR_SCALE r,x,y -> r = x * 2^round(y)
; MR_CSCALE r,x,pwr2 -> r = x * 2^pwr2
; MR_FROM_STR r,literal -> Convert numeric literal to MREAL value. The literal could be of the format:
;
; Description | Example | Notes | regex (PCRE)
; -----------------------------+-------------+---------------------------+---------------------------------------------------------------
; hexadecimal integer literal | 0ffh | | ^[+-]?[0-9][0-9a-fA-F]*[Hh]$
; -----------------------------+-------------+---------------------------+---------------------------------------------------------------
; MASM hexadecimal floating | 07f800000r | Remarks the type specific | ^[+-]?[0-9][0-9a-fA-F]*[Rr]$
; point initializer | | size constraints |
; -----------------------------+-------------+---------------------------+---------------------------------------------------------------
; decimal integer literal | 123 | | ^[+-]?[0-9]+[Tt]?$
; -----------------------------+-------------+---------------------------+---------------------------------------------------------------
; decimal floating point | -1.0E-3 | The exponent should be in | ^[+-]?[0-9]+\.[0-9]*([Ee][+-]?[0-9]+)?$
; literal | 123.4 | the range -4800 to 4800 |
; -----------------------------+-------------+---------------------------+---------------------------------------------------------------
; IEEE754-2008 hexadecimal- | 0x123 | | ^[+-]*0[Xx][0-9a-fA-F]+\.?([0-9a-fA-F]+)?([Pp][+-]?[0-9]+)?$
; significant character | 0x123.FFF | | or
; sequence | 0xF.1p-123 | | ^[+-]*0[Xx]\.?[0-9a-fA-F]+([Pp][+-]?[0-9]+)?$
; -----------------------------+-------------+---------------------------+---------------------------------------------------------------
;
; Leading and trailing blanks are ignored. Hexadecimal literals always produce correctly rounded MREAL values.
; For decimal values the result is only correctly rounded, if the value is representable as quotient or product
; of two integers, whereby the decimal exponent of these integers is below or equal to 105.
; e.g. for values with 30 significant digits the decimal exponent range is at least -75 to 75. For 20 digits the range is extended to -85 to 85.
; Decimal values with larger exponents are approximated - in such cases (and only in this cases) the flag MREAL_INEXACT is set to -2.
;
; MR_LOAD_CONST r,name,pwr2 -> Load specified constant.
; The name is not case-sensitive and could be: pi, rpi, e, one, zero, deg, rad, Infinity, NaN , max, min.
; Except for NaN, the names can be prefixed with a sign.
; The parameter pwr2 is added to the binary exponent of finite values.
; For more details see the macro declaration.
; MR_SET_CONST name,flg,
; exp,n,
; mantissa -> Store MREAL constant. Parameters:
; flg : Could be <+>,<->,<+Infinity>,<-Infinity>,<NaN> or <zero>.
; exp : The exponent for finite values.
; n : Number of mantissa WORDs.
; mantissa : [VARARG] Mantissa WORDs. The values will be masked with 0ffffh, missing values are set to zero.
; This macro does fill the equates MREAL_&name&_n and MREAL_&name&_nSig.
; Remarks that the macro assumes the values to be normalized to 2^1 = 1 (as for IEEE binary interchange formats).
;
; MREAL x = literal1,
; y = literal2, ... -> Initialize one or more MREAL values from numeric literals. To override the default precision, each assignment can contain
; a brace-expression that specifies the precision to use. For example, "MREAL x{8} = 0.123" initialize x with a precision of 8*16 bit.
;
; Functions:
; MR_TO_IEEE(<type>,x) := Convert x to target precision and return a text macro that holds the corresponding hexadecimal floating point initializer.
; Type specifier can be: REAL4, REAL8, REAL10, single, double, double-extended,
; binary16, binary32, binary64.
; Due to a bug in MASM v6-7 this macro cannot directly used to initialize REAL10 values - use MR_DEF_REAL10 instead.
; For more details see the macro declaration.
; MR_TO_INT32(x,errVal) := returns x rounded to an integer. If the rounded value is not in the range -2^31 to 2^31-1, then errVal is returned.
; If errVal is non-numeric, an error is thrown instead.
; MR_TO_UINT32(x,errVal) := returns x rounded to an unsigned integer. If the rounded value is not in the range 0 to 2^32-1, then errVal is returned.
; If errVal is non-numeric, an error is thrown instead.
; MR_TO_INT64(x,errVal) := returns x rounded to an integer. If the rounded value is not in the range -2^63 to 2^63-1, then errVal is returned.
; If errVal is non-numeric, an error is thrown instead.
; MR_TO_UINT64(x,errVal) := returns x rounded to an unsigned integer. If the rounded value is not in the range 0 to 2^64-1, then errVal is returned.
; If errVal is non-numeric, an error is thrown instead.
; MR_IS_ZERO(x) := returns TRUE if x==0
; MR_IS_SIGN_MINUS(x) := returns TRUE if x<0 (also for -Infinity)
; MR_IS_NORMAL(x) := returns TRUE if x is not: zero, +-Infinity or NaN. (In other words: returns TRUE if the value requires a mantissa)
; MR_IS_FINITE(x) := returns TRUE if x is not: +-Infinity or NaN
; MR_IS_INFINITE(x) := returns TRUE if x is +-Infinity
; MR_IS_NAN(x) := returns TRUE if x is NaN
; MR_EQ(x,y) := returns TRUE if x == y
; MR_NE(x,y) := returns TRUE if x != y
; MR_GT(x,y) := returns TRUE if x > y
; MR_GE(x,y) := returns TRUE if x >= y
; MR_LT(x,y) := returns TRUE if x < y
; MR_LE(x,y) := returns TRUE if x <= y
; MR_UN(x,y) := returns TRUE if unordered
; MR_NOT_UN(x,y) := returns TRUE if not unordered
; MR_NOT_GT(x,y) := returns TRUE if x <= y or unordered
; MR_GT_UN(x,y) := returns TRUE if x > y or unordered
; MR_LT_UN(x,y) := returns TRUE if x < y or unordered
; MR_NOT_LT(x,y) := returns TRUE if x >= y or unordered
; MR_TO_DECIMAL(x,N) := returns a decimal literal that approximates the MREAL value x. This macro is mainly intended
; for debugging purpose -> Do not use this macro to initialize REAL4/8/10 values!
; The parameter N specifies the number of significant decimal digits (default=8).
; MR_TO_IEEE_HEX_SEQ(x,N) := returns IEEE754-2008 hexadecimal-significant character sequence for x using N hexadecimal mantissa digits.
; If N is zero, (=default value) all mantissa digits are used.
; MR_EXPONENT(x) := returns the equate that hold the binary exponent of MREAL value x.
; MR_ID_IS_MREAL(ID) := returns TRUE if ID is an MREAL value
;
; MR_GET_N_SIGNIFICANT_WORDS(x,n) := returns the number of significant mantissa WORDs. n is the number of mantissa WORDs.
; MR_GET_N_SIGNIFICANT_BITS(x,n) := returns the number of significant bits. n is the number of mantissa WORDs.
;
;
; Global states
;
; The global precision setting, rounding mode and exponent limits are stored
; in the equates:
; MREAL_XDIM := number of precision bits in multiples of 16.
; default value: 4 = 64 bit precision
; MREAL_ROUND_MODE := rounding mode -> see declaration of MRRM_* constants.
; default value: MRRM_ROUND_TO_NEAREST_TIES_TO_EVEN
; MREAL_MAX_EXP := maximal binary exponent.
; default value: 16382 -> correspond to double-extended precision values (REAL10)
; MREAL_MIN_EXP := minimal binary exponent.
; default value: -16381 -> correspond to double-extended precision values (REAL10)
;
; These equates can be dynamically changed, but MREAL values created with different
; precision setting should not be mixed - instead the values should be converted using the MR_CONVERT macro.
; All arithmetic macros have additional parameters that allows to locally overwrite the global settings
; (commonly named: "n", "nx", "ny", "nr" or "p" for the precision and "rm" for the rounding mode).
;
; MASM environment
; - The macros are case-sensitive thus OPTION CASEMAP:NONE is needed.
; - The expression word size must be at least 32 bit (OPTION EXPR32, default for MASM v6+).
; - The macros assumes radix 10 (MASM default radix).
;
; MASM limits
; The memory usage is the most important limiting factor of the MREAL macros. Each macro line and macro loop iteration
; enlarges the "virtual" source file while assembling and thus MASM's memory usage.
; Remarks that the memory usage will dramatically increase if a listing is created (command line option "/Fl").
;
; Simulating IEEE754 single and double precision arithmetic (24 and 53 bit precision)
; This could be done by using an higher precision for the arithmetic (e.g. 32 bit for
; single precision and 64 bit for double precision) and call MR_ROUND after
; each operation as:
; MR_ROUND x,x,24,<bits> ; round x to single precision
; MR_ROUND x,x,53,<bits> ; round x to double precision
;
; Creating MREAL constants in computer algebra systems:
; The following pseudo code shows how a conversion from any finite
; nonzero value to MREAL could be done:
;
; // Some definitions:
; // sgn(x) -> returns a boolean value: true => x is negative, false => x is positive.
; // abs(x) -> gives the absolute value of x.
; // log2(x) -> returns the logarithm of x to base 2.
; // floor(x) -> returns the largest integer not greater than x.
; // round(x) -> round x to an integer in wished rounding mode.
; // "^" -> means exponentiation.
; // assert: c -> test condition c and throws an error if not true.
; // w[] -> is array 0 to nw-1 of unsigned integer (at least 16 bit). w[0] holds the most significant bits.
;
; toMREAL(x,nw) { // x = value to convert, nw = number of mantissa words (word = unsigned 16 bit)
; sign = sgn(x);
; a = abs(x);
; e = floor(log2(a));
; mx = round(a*2^(-e-1+nw*16))*2^(-nw*16);
; for(i=0; i<nw; i++) {
; v = mx * 2^16;
; w[i] = floor(v);
; mx = v - w[i];
; }
; assert: mx == 0;
; return {sign,e,nw,w};
; }
;
; The return vector {sign,e,nw,w} could be used to setup a call to MR_SET_CONST.
;
; Changelog
; 27.05.2014 Version 1.0.1
; bugfix: - MR_TO_DECIMAL(): mrtiTmp was used, even if it was invalid.
; 26.06.2014 Version 1.0.2
; added: - MREAL macro.
; 26.06.2014 Version 1.0.3
; improvement: - test for case-sensitive symbol recognition added (option casemap:none)
; bugfix: - MREAL-macro: did not work correct for integer literals greater than 32 bit (affects only ml64.exe and jWasm).
; 25.09.2015 Version 1.0.4
; added: - MR_ID_IS_MREAL macro
; improvement: - include guard added
; bugfix: - @ScanForFlt: wrong position were returned for integers. Also partial correct literals were discarded if parameter chr was blank.
; - MR_SCALE: wrong input operand was used as exponent.
; change: - MR_DECL_REAL10 macro has been renamed to MR_DEF_REAL10. To keep backward compatibility MR_DECL_REAL10 is an alias for MR_DEF_REAL10.
;
; Literature
; [1] J.-M. Muller, N. Brisebarre, F. de Dinechin, C.-P. Jeannerod, V. Lefevre, G. Melquiond, N. Revol, D. Stehle, S. Torres.
; Handbook of Floating-Point Arithmetic. Birkhäuser Boston, 2009.
; [2] U. Kulisch. Computer Arithmetic and Validity; Theory, Implementation, and Applications.
; de Gruyter Berlin/Boston, 2nd edition, 2013.
; [3] J.-M. Muller. Elementary Functions, Algorithms and Implementation.
; Birkhäuser Boston, 2nd edition, 2006.
; [4] I. Koren. Computer Arithmetic Algorithms.
; A K Peters, Natick Massachusetts, 2nd edition, 2002.
; [5] IEEE Computer Society. IEEE Standard for Floating-Point Arithmetic; IEEE Std 754-2008.
; The Institute of Electrical and Electronics Engineers, New York. 2008.
;
IFNDEF MR_VERSION
MR_VERSION EQU 104 ; 1.0.4
MREAL_XDIM = 4
MREAL_WMSK EQU 0ffffh
MREAL_MAX_EXP EQU (16383+1) ; default values are compatible with REAL10
MREAL_MIN_EXP EQU (2-16383) ;
;/* symbol recognition must be case-sensitive */
IFDEF MrEaL_XdIm
.err <option casemap:none is needed>
ENDIF
;/* rounding modes */
MRRM_ROUND_TO_NEAREST_TIES_TO_EVEN EQU 0 ;; IEEE 754 default mode; tie-breaking rule: round half to even; also called "round to even" or "bankers rounding"
MRRM_ROUND_TOWARD_NEGATIVE EQU 1
MRRM_ROUND_TOWARD_POSITIVE EQU 2
MRRM_ROUND_TOWARD_ZERO EQU 3
MRRM_ROUND_TO_NEAREST_TIES_AWAY_FROM_ZERO EQU 4 ;; tie-breaking rule: round half away from zero
MRRM__MINVALUE EQU 0
MRRM__MAXVALUE EQU 4
;/* alias */
MRRM_TRUNCATE EQU MRRM_ROUND_TOWARD_ZERO
MRRM_ROUND_TO_EVEN EQU MRRM_ROUND_TO_NEAREST_TIES_TO_EVEN
MRRM_ROUND_DOWN EQU MRRM_ROUND_TOWARD_NEGATIVE
MRRM_ROUND_UP EQU MRRM_ROUND_TOWARD_POSITIVE
;/* short names */
MRRM_NEAR_EVEN = MRRM_ROUND_TO_NEAREST_TIES_TO_EVEN
MRRM_NEAR_AWAY = MRRM_ROUND_TO_NEAREST_TIES_AWAY_FROM_ZERO
;/* set default rounding mode */
MREAL_ROUND_MODE = MRRM_ROUND_TO_NEAREST_TIES_TO_EVEN
;/* error control values (boolean values: 0 == FALSE, -1 == TRUE) */
MREAL_ERROR_FOR_NAN_INPUT = 0 ; throw error for NaN and +-Infinity as macro input
MREAL_ERROR_FOR_NAN_OUTPUT = 0 ; throw error for NaN and +-Infinity as macro result
MREAL_ERROR_FOR_DIV_ZERO = -1
MREAL_UNDERFLOW_IS_ERROR = 0 ; throw error if the exponent of the result underflows (exponent < MREAL_MIN_EXP)
MREAL_OVERFLOW_IS_ERROR = 0 ; throw error if the exponent of the result overflows (exponent > MREAL_MAX_EXP)
;/* inexact handling */
MREAL_TEST_INEXACT = 0
MREAL_INEXACT = 0
;/* MREAL-flags (do not change!) */
MREAL_FLG_VALID EQU 0
MREAL_FLG_ZERO EQU 1
MREAL_FLG_INF EQU 2
MREAL_FLG_NAN EQU 4
MREAL_FLG_SIGN EQU 080000000h
;/* masks */
MREAL_FLG_NON_NUMERIC_TEST EQU 07ffffffeh
MREAL_FLG_NO_MANTISSA_TEST EQU 07fffffffh
MREAL_ALL_FLGS = MREAL_FLG_ZERO OR MREAL_FLG_INF OR MREAL_FLG_NAN OR MREAL_FLG_SIGN
MREAL_SINGLE_FLGS TEXTEQU <MREAL_FLG_ZERO,MREAL_FLG_NAN>
;/* MR_GLB_STATE_STACK is used by MR_PUSH/POP_STATE */
MR_GLB_STATE_STACK = 0
;;/**
;; * Push one or more equates on a virtual stack.
;; */
MR_PUSH_STATE macro states:VARARG
MR_GLB_STATE_STACK = MR_GLB_STATE_STACK + 1
@CatStr(<MRGSS_STATES>,%MR_GLB_STATE_STACK) TEXTEQU <&states>
FOR state,<&states>
@CatStr(<MRGSS_&state&>,%MR_GLB_STATE_STACK) = state
ENDM
endm
;;/* Pop previously saved equates from virtual stack */
MR_POP_STATE macro
IFE MR_GLB_STATE_STACK
.err <stack underrun>
EXITM
ENDIF
% FOR state,<@CatStr(<MRGSS_STATES>,%MR_GLB_STATE_STACK)>
state = @CatStr(<MRGSS_&state&>,%MR_GLB_STATE_STACK)
ENDM
MR_GLB_STATE_STACK = MR_GLB_STATE_STACK - 1
endm
;;/* returns TRUE, if ID is a MREAL value */
MR_ID_IS_MREAL macro ID:req
IFNDEF MREAL_&ID&_flg
EXITM <0>
ENDIF
EXITM <-1>
endm
;;/* create MREAL value and set it to zero (also all mantissa WORDs) */
MR_CREATE macro name:req,n:=<MREAL_XDIM>
MREAL_&name&_flg = MREAL_FLG_ZERO
MREAL_&name&_exp = 0
mrc_cntr = 0
REPEAT n
% @CatStr(<MREAL_&name&_w>,%mrc_cntr) = 0
mrc_cntr = mrc_cntr + 1
ENDM
endm
MR_SET_ZERO EQU MR_CREATE
;;/* Copy src to dest. */
MR_MOV macro dest:req,src:req,n:=<MREAL_XDIM>
IFIDN <&dest>,<&src>
EXITM
ENDIF
MREAL_&dest&_exp = MREAL_&src&_exp
MREAL_&dest&_flg = MREAL_&src&_flg
mrc_cntr = 0
REPEAT n
mrc_tcntr TEXTEQU %mrc_cntr
% MREAL_&dest&_w&mrc_tcntr& = MREAL_&src&_w&mrc_tcntr&
mrc_cntr = mrc_cntr + 1
ENDM
endm
; This macro assumes input values normalized to 2^0 = 1 (as for IEEE754 binary interchange formats).
; flg = <+> or blank : positive number
; <-> : negative number
; <zero> :
; <+Infinity> :
; <-Infinity> :
; <NaN> : not a number
; exp = binary exponent (2^exp) in the range MREAL_MIN_EXP to MREAL_MAX_EXP (default: -16382 to 16383)
; mantissa = mantissa WORDs starting with the most significant WORD (holding the leading 1).
; The values are masked with 0FFFFh. Unspecified WORDs are set to zero.
; example:
; +1.0: MR_RAW_SET cOne,+,0,8000h
; -0.5: MR_RAW_SET cMinusHalf,-,-1,8000h
; +INFINITY: MR_RAW_SET cInf,+Infinity
; 0.0: MR_RAW_SET cZero,zero
MR_RAW_SET macro name,flg:=<>,exp:=<0>,mantissa:VARARG
MR_RAW_SET_N name,flg,exp,,mantissa
endm
MR_RAW_SET_N macro name,flg:=<>,exp:=<0>,n:=<MREAL_XDIM>,mantissa:VARARG
IFB <&flg>
MREAL_&name&_flg = MREAL_FLG_VALID
ELSEIFIDNI <&flg>,<zero>
MREAL_&name&_flg = MREAL_FLG_ZERO
ELSEIFIDNI <&flg>,<+>
MREAL_&name&_flg = MREAL_FLG_VALID
ELSEIFIDNI <&flg>,<->
MREAL_&name&_flg = MREAL_FLG_SIGN
ELSEIFIDNI <&flg>,<+Infinity>
MREAL_&name&_flg = MREAL_FLG_INF
ELSEIFIDNI <&flg>,<-Infinity>
MREAL_&name&_flg = MREAL_FLG_INF OR MREAL_FLG_SIGN
ELSEIFIDNI <&flg>,<NaN>
MREAL_&name&_flg = MREAL_FLG_NAN
ELSE
.err <invalid flag-specifier for &name: flg>
EXITM
ENDIF
IF (exp LT MREAL_MIN_EXP) OR (exp GT MREAL_MAX_EXP)
.err <exponent value of &name is out of range>
EXITM
ENDIF
MREAL_&name&_exp = exp + 1
mrc_cntr = 0
mrc_nzero = 0
mrc_tcntr TEXTEQU %mrc_cntr
FOR arg,<&mantissa>
IFNB <&arg>
IF mrc_cntr GE n
.err @CatStr(<to many arguments for mant>,<issa of &name>)
EXITM
ENDIF
IF (mrc_cntr EQ 0) AND ((MREAL_&name&_flg AND MREAL_FLG_NO_MANTISSA_TEST) EQ 0) AND ((arg AND 8000h) EQ 0)
.err @CatStr(<man>,<tissa of &name is denormalized>)
EXITM
ENDIF
% MREAL_&name&_w&mrc_tcntr& = (arg) AND MREAL_WMSK
mrc_nzero = mrc_nzero+1 AND ((arg) AND MREAL_WMSK) EQ 0
ELSE
% MREAL_&name&_w&mrc_tcntr& = 0
mrc_nzero = mrc_nzero + 1
ENDIF
mrc_cntr = mrc_cntr + 1
mrc_tcntr TEXTEQU %mrc_cntr
ENDM
WHILE mrc_cntr LT n
% MREAL_&name&_w&mrc_tcntr& = 0
mrc_nzero = mrc_nzero + 1
mrc_cntr = mrc_cntr + 1
mrc_tcntr TEXTEQU %mrc_cntr
ENDM
MREAL_&name&_n = n
MREAL_&name&_nSig = n-mrc_nzero
endm
MR_SET_CONST EQU MR_RAW_SET_N
MR_RAW_COMPOSE macro name,flg,exp,mantissa_src,n:=<MREAL_XDIM>
MREAL_&name&_exp = exp
MREAL_&name&_flg = flg
mrc_cntr = 0
mrc_tcntr TEXTEQU %mrc_cntr
WHILE mrc_cntr LT n
% MREAL_&name&_w&mrc_tcntr& = MREAL_&mantissa_src&_w&mrc_tcntr& AND MREAL_WMSK
mrc_cntr = mrc_cntr + 1
mrc_tcntr TEXTEQU %mrc_cntr
ENDM
endm
;;/**
;; * Produce the largest postive finite value (according
;; * to the current precision and exponent settings) and negate it,
;; * if "sign" is not zero.
;; */
MR_RAW_MAXVALUE macro name:req,sign:=<0>,n:=<MREAL_XDIM>,emax:=<MREAL_MAX_EXP>
MREAL_&name&_exp = emax
MREAL_&name&_flg = (sign NE 0) AND MREAL_FLG_SIGN
mrc_cntr = 0
WHILE mrc_cntr LT n
@CatStr(<MREAL_&name&_w>,%mrc_cntr) = 0ffffh
mrc_cntr = mrc_cntr + 1
ENDM
endm
;;/**
;; * Produce the smallest postive finite nonzero value (according
;; * to the current precision and exponent settings) and negate it,
;; * if "sign" is not zero.
;; */
MR_RAW_MINVALUE macro name:req,sign:=<0>,n:=<MREAL_XDIM>,emin:=<MREAL_MIN_EXP>
MREAL_&name&_exp = emin
MREAL_&name&_flg = (sign NE 0) AND MREAL_FLG_SIGN
MREAL_&name&_w0 = 8000h
mrc_cntr = 1
WHILE mrc_cntr LT n
@CatStr(<MREAL_&name&_w>,%mrc_cntr) = 0
mrc_cntr = mrc_cntr + 1
ENDM
endm
; return: 0/-1 => invalid/valid. Error description is emitted to the build console
MR_RAW_IS_VALID macro name,n:=<MREAL_XDIM>
mrriv_exp? = -1
mrriv_expinv? = 0
mrriv_all_mantissa? = -1
mrriv_flg? = -1
mrriv_flginv? = 0
mrriv_denorm? = 0
mrriv_inv_mx? = 0
IFNDEF MREAL_&name&_exp
mrriv_exp? = 0
ELSEIF (MREAL_&name&_exp LT MREAL_MIN_EXP) OR (MREAL_&name&_exp GT MREAL_MAX_EXP)
mrriv_expinv? = -1
ENDIF
IFNDEF MREAL_&name&_flg
mrriv_flg? = 0
ELSEIF (MREAL_&name&_flg AND (NOT MREAL_ALL_FLGS)) NE 0
mrriv_flginv? = -1
ELSEIF ((MREAL_&name&_flg AND MREAL_FLG_SIGN ) NE 0) AND ((MREAL_&name&_flg AND (NOT (MREAL_FLG_INF OR MREAL_FLG_SIGN))) NE 0)
mrriv_flginv? = -1
ELSE
% FOR msk,<&MREAL_SINGLE_FLGS>
IF ((MREAL_&name&_flg AND msk) NE 0) AND ((MREAL_&name&_flg AND (NOT (msk))) NE 0)
mrriv_flginv? = -1
EXITM
ENDIF
ENDM
ENDIF
mrriv_missing TEXTEQU <>
mrriv_invmx TEXTEQU <>
mrriv_mc = 0
mrriv_cntr = 0
mrriv_tcntr TEXTEQU %mrriv_cntr
WHILE mrriv_cntr LT n
% IFNDEF MREAL_&name&_w&mrriv_tcntr&
IFB mrriv_missing
mrriv_missing TEXTEQU mrriv_tcntr
ELSE
mrriv_missing TEXTEQU mrriv_missing,<,>,mrriv_tcntr
ENDIF
mrriv_mc = mrriv_mc + 1
ELSE
IF mrriv_cntr EQ 0
% IFE MREAL_&name&_w&mrriv_tcntr& AND 8000h
mrriv_denorm? = -1
ENDIF
ENDIF
% IF (MREAL_&name&_w&mrriv_tcntr& AND (NOT MREAL_WMSK)) NE 0
IFB mrriv_invmx
mrriv_invmx TEXTEQU mrriv_tcntr
ELSE
mrriv_invmx TEXTEQU mrriv_invmx,<,>,mrriv_tcntr
ENDIF
ENDIF
ENDIF
mrriv_cntr = mrriv_cntr + 1
mrriv_tcntr TEXTEQU %mrriv_cntr
ENDM
IFNB mrriv_missing
mrriv_all_mantissa? = 0
ENDIF
IFNB mrriv_invmx
mrriv_inv_mx? = -1
ENDIF
IF mrriv_flg? AND mrriv_exp? AND mrriv_all_mantissa? AND (NOT mrriv_flginv?)
IF MREAL_&name&_flg AND (MREAL_FLG_NON_NUMERIC_TEST OR MREAL_FLG_ZERO)
EXITM <-1>
ENDIF
ENDIF
IF mrriv_exp? AND mrriv_all_mantissa? AND (NOT mrriv_expinv?) AND (NOT mrriv_inv_mx?) AND (NOT mrriv_denorm?) AND mrriv_flg? AND (NOT mrriv_flginv?)
EXITM <-1>
ENDIF
IF (NOT mrriv_flg?) AND (NOT mrriv_exp?) AND (mrriv_mc EQ n)
echo symbol <&name> is not a MREAL-value
EXITM <0>
ENDIF
echo MREAL <&name> is invalid because of:
IFE mrriv_flg?
echo . - has no flags (missing EQU)
ENDIF
IF mrriv_flginv?
echo . - invalid flags
ENDIF
IFE mrriv_exp?
echo . - has no exponent (missing EQU)
ENDIF
IF mrriv_expinv?
echo . - exponent value is out of range (MREAL_MIN_EXP to MREAL_MAX_EXP)
ENDIF
IFE mrriv_all_mantissa?
% echo . - one or more mantissa values are missing (EQU). Indexes: &mrriv_missing&
ENDIF
IF mrriv_inv_mx?
% echo . - one or more mantissa values are out of range. Indexes: &mrriv_invmx&
ENDIF
IF mrriv_denorm?
echo . - the mantissa is denormalized
ENDIF
IF mrriv_all_mantissa? AND mrriv_flg? AND mrriv_exp?
EXITM <-1>
ELSE
EXITM <0>
ENDIF
endm
; print MREAL "name" to the build console: <+-><hexadecimal mantissa>*2^<decimal exponent>
MR_RAW_OUT macro name:req,n:=<MREAL_XDIM>,accum
IFE MR_RAW_IS_VALID(name,n)
EXITM
ENDIF
IF (MREAL_&name&_flg AND MREAL_FLG_ZERO) NE 0
mrc_outtxt TEXTEQU <name is: zero (0)>
ELSEIF ((MREAL_&name&_flg AND MREAL_FLG_INF) NE 0) AND ((MREAL_&name&_flg AND MREAL_FLG_SIGN) NE 0)
mrc_outtxt TEXTEQU <name is: -Infinity>
ELSEIF (MREAL_&name&_flg AND MREAL_FLG_INF) NE 0
mrc_outtxt TEXTEQU <name is: +Infinity>
ELSEIF (MREAL_&name&_flg AND MREAL_FLG_NAN) NE 0
mrc_outtxt TEXTEQU <name is: not a number (NaN)>
ELSE
mrc_outtxt TEXTEQU <name is: >
IF (MREAL_&name&_flg AND MREAL_FLG_SIGN) NE 0
mrc_outtxt TEXTEQU mrc_outtxt,<->
ELSE
mrc_outtxt TEXTEQU mrc_outtxt,<+>
ENDIF
mrc_cntr = 0
WHILE mrc_cntr LT n AND mrc_cntr LT 32
mrc_val = @CatStr(<MREAL_&name&_w>,%mrc_cntr)
.radix 16
mrc_txt TEXTEQU %mrc_val
.radix 10
IF @SizeStr(%mrc_txt) EQ 1
mrc_txt TEXTEQU <000>,mrc_txt
ELSEIF @SizeStr(%mrc_txt) EQ 2
mrc_txt TEXTEQU <00>,mrc_txt
ELSEIF @SizeStr(%mrc_txt) EQ 3
mrc_txt TEXTEQU <0>,mrc_txt
ENDIF
IF mrc_cntr NE 0
mrc_txt TEXTEQU <_>,mrc_txt
ENDIF
mrc_outtxt TEXTEQU mrc_outtxt,mrc_txt
mrc_cntr = mrc_cntr + 1
ENDM
mrc_accum TEXTEQU <>
IFNB <&accum>
WHILE mrc_cntr LT n*2+1
mrc_tcntr TEXTEQU %mrc_cntr
% IFNDEF MREAL_&name&_w&mrc_tcntr&
EXITM
ENDIF
% mrc_val = MREAL_&name&_w&mrc_tcntr&
.radix 16
mrc_txt TEXTEQU %mrc_val
.radix 10
IF @SizeStr(%mrc_txt) EQ 1
mrc_txt TEXTEQU <000>,mrc_txt
ELSEIF @SizeStr(%mrc_txt) EQ 2
mrc_txt TEXTEQU <00>,mrc_txt
ELSEIF @SizeStr(%mrc_txt) EQ 3
mrc_txt TEXTEQU <0>,mrc_txt
ENDIF
mrc_accum TEXTEQU mrc_accum,<_>,mrc_txt
mrc_cntr = mrc_cntr + 1
ENDM
ENDIF
IF n LT 32
mrc_outtxt TEXTEQU mrc_outtxt,mrc_accum,<*2^>,@CatStr(%MREAL_&name&_exp-1)
ENDIF
ENDIF
%echo mrc_outtxt
IF n GT 32
mrc_cntr = 32
WHILE mrc_cntr LT n
mrc_outtxt TEXTEQU <>
REPEAT 32
IF mrc_cntr GE n
EXITM
ENDIF
mrc_val = @CatStr(<MREAL_&name&_w>,%mrc_cntr)
.radix 16
mrc_txt TEXTEQU %mrc_val
.radix 10
IF @SizeStr(%mrc_txt) EQ 1
mrc_txt TEXTEQU <000>,mrc_txt
ELSEIF @SizeStr(%mrc_txt) EQ 2
mrc_txt TEXTEQU <00>,mrc_txt
ELSEIF @SizeStr(%mrc_txt) EQ 3
mrc_txt TEXTEQU <0>,mrc_txt
ENDIF
IF mrc_cntr NE 0
mrc_txt TEXTEQU <_>,mrc_txt
ENDIF
mrc_outtxt TEXTEQU mrc_outtxt,mrc_txt
mrc_cntr = mrc_cntr + 1
ENDM
IF mrc_cntr EQ n
%echo @CatStr(%mrc_outtxt,<*2^>,%MREAL_&name&_exp-1)
ELSE
%echo mrc_outtxt
ENDIF
ENDM
ENDIF
endm
;/* shift mantissa bits of r s-times left (mantissa=mantissa*2^s) */
MR_LSHIFT macro r,s,n:=<MREAL_XDIM>
IFE s
EXITM
ENDIF
mrls_iHigh = 0
mrls_tiHigh TEXTEQU %mrls_iHigh
IF s LT 16*(n)
mrls_iLow = s/16
mrls_tiLow TEXTEQU %mrls_iLow
mrls_lshift = s mod 16
mrls_rshift = 16 - mrls_lshift
mrls_limit = n - 1
WHILE mrls_iLow LT mrls_limit
mrls_tiLowP1 TEXTEQU %mrls_iLow+1
% MREAL_&r&_w&mrls_tiHigh& = LOWWORD (MREAL_&r&_w&mrls_tiLow& SHL mrls_lshift OR MREAL_&r&_w&mrls_tiLowP1& SHR mrls_rshift)
mrls_iHigh = mrls_iHigh + 1
mrls_tiHigh TEXTEQU %mrls_iHigh
mrls_iLow = mrls_tiLowP1
mrls_tiLow TEXTEQU mrls_tiLowP1
ENDM
% MREAL_&r&_w&mrls_tiHigh& = LOWWORD (MREAL_&r&_w&mrls_tiLow& SHL mrls_lshift)
mrls_iHigh = mrls_iHigh + 1
mrls_tiHigh TEXTEQU %mrls_iHigh
ENDIF
WHILE mrls_iHigh LE (n - 1)
% MREAL_&r&_w&mrls_tiHigh& = 0
mrls_iHigh = mrls_iHigh + 1
mrls_tiHigh TEXTEQU %mrls_iHigh
ENDM
endm
;/* shift mantissa bits of r s-times right (mantissa=mantissa*2^(-s)) */
MR_RSHIFT macro r,s,n:=<MREAL_XDIM>
IFE s
EXITM
ENDIF
mrrs_iLow = n - 1
mrrs_tiLow TEXTEQU %mrrs_iLow
IF s LT 16*(n)
mrrs_iHigh = mrrs_iLow - s/16
mrrs_tiHigh TEXTEQU %mrrs_iHigh
mrrs_rshift = s mod 16
mrrs_lshift = 16 - mrrs_rshift
WHILE mrrs_iHigh GT 0
mrrs_tiHighM1 TEXTEQU %mrrs_iHigh-1
% MREAL_&r&_w&mrrs_tiLow& = LOWWORD (MREAL_&r&_w&mrrs_tiHigh& SHR mrrs_rshift OR MREAL_&r&_w&mrrs_tiHighM1& SHL mrrs_lshift)
mrrs_iHigh = mrrs_tiHighM1
mrrs_tiHigh TEXTEQU mrrs_tiHighM1
mrrs_iLow = mrrs_iLow - 1
mrrs_tiLow TEXTEQU %mrrs_iLow
ENDM
% MREAL_&r&_w&mrrs_tiLow& = LOWWORD (MREAL_&r&_w&mrrs_tiHigh& SHR mrrs_rshift)
mrrs_iLow = mrrs_iLow - 1
mrrs_tiLow TEXTEQU %mrrs_iLow
ENDIF
WHILE mrrs_iLow GE 0
% MREAL_&r&_w&mrrs_tiLow& = 0
mrrs_iLow = mrrs_iLow - 1
mrrs_tiLow TEXTEQU %mrrs_iLow
ENDM
endm
MR_RSHIFT_1 macro r,n:=<MREAL_XDIM>
mrrs_cntr = 0
mrrs_tmp = 0
REPEAT n
mrrs_tcntr TEXTEQU %mrrs_cntr
% mrrs_tmp = MREAL_&r&_w&mrrs_tcntr& OR LOWWORD mrrs_tmp SHL 16
% MREAL_&r&_w&mrrs_tcntr& = LOWWORD (mrrs_tmp SHR 1)
mrrs_cntr = mrrs_cntr + 1
ENDM
endm
MR_LSHIFT_1 macro r,n:=<MREAL_XDIM>
mrrs_cntr = (n)-1
mrrs_tmp = 0
REPEAT n
mrrs_tcntr TEXTEQU %mrrs_cntr
% mrrs_tmp = MREAL_&r&_w&mrrs_tcntr& SHL 16 OR HIGHWORD mrrs_tmp
% MREAL_&r&_w&mrrs_tcntr& = HIGHWORD (mrrs_tmp SHL 1)
mrrs_cntr = mrrs_cntr - 1
ENDM
endm
MR_PREPARE_ACCUMULATOR macro name,s:=<MREAL_XDIM>,n:=<MREAL_XDIM*2+1>
mrpa_cntr = s
WHILE mrpa_cntr LT n
@CatStr(<MREAL_&name&_w>,%mrpa_cntr) = 0
mrpa_cntr = mrpa_cntr + 1
ENDM
endm
;;/* returns the number of significant bits in r */
MR_GET_N_SIGNIFICANT_BITS macro r:req,n:=<MREAL_XDIM>
IF MREAL_&r&_flg AND MREAL_FLG_ZERO
EXITM <0>
ELSEIF MREAL_&r&_flg AND MREAL_FLG_NO_MANTISSA_TEST
.err <invalid input value: r>
EXITM <0>
ENDIF
mrgnsb_cntr = n-1
REPEAT n
IF @CatStr(<MREAL_&r&_w>,%mrgnsb_cntr)
EXITM
ENDIF
mrgnsb_cntr = mrgnsb_cntr - 1
ENDM
IF mrgnsb_cntr LT 0
.err <denormal mantissa: r>
EXITM <0>
ENDIF
mrgnsb_val = @CatStr(<MREAL_&r&_w>,%mrgnsb_cntr)
.radix 16
mrgnsb_txt TEXTEQU %mrgnsb_val
.radix 10
mrgnsb_size SIZESTR mrgnsb_txt
IF @CatStr(<0>,@SubStr(%mrgnsb_txt,%mrgnsb_size,1),<h>)
mrgnsb_pos = mrgnsb_size
ELSEIF @CatStr(<0>,@SubStr(%mrgnsb_txt,%mrgnsb_size-1,1),<h>)
mrgnsb_pos = mrgnsb_size-1
ELSEIF @CatStr(<0>,@SubStr(%mrgnsb_txt,%mrgnsb_size-2,1),<h>)
mrgnsb_pos = mrgnsb_size-2
ELSEIF @CatStr(<0>,@SubStr(%mrgnsb_txt,%mrgnsb_size-3,1),<h>)
mrgnsb_pos = mrgnsb_size-3
ELSE
.err <invalid matnissa WORD in r>
EXITM <0>
ENDIF
mrgnsb_txt SUBSTR <434243414342434>,@CatStr(<0>,@SubStr(%mrgnsb_txt,%mrgnsb_pos,1),<h>),1
EXITM %mrgnsb_cntr*16+(mrgnsb_pos+(4-mrgnsb_size)-1)*4+mrgnsb_txt
endm
;;/* returns the number of significant WORDs in r */
MR_GET_N_SIGNIFICANT_WORDS macro r:req,n:=<MREAL_XDIM>
IF MREAL_&r&_flg AND MREAL_FLG_ZERO
EXITM <0>
ELSEIF MREAL_&r&_flg AND MREAL_FLG_NO_MANTISSA_TEST
.err <invalid input value: r>
EXITM <0>
ENDIF
mrgnsb_cntr = n-1
REPEAT n
IF @CatStr(<MREAL_&r&_w>,%mrgnsb_cntr)
EXITM
ENDIF
mrgnsb_cntr = mrgnsb_cntr - 1
ENDM
IF mrgnsb_cntr LT 0
.err <denormal mantissa: r>
EXITM <0>
ENDIF
EXITM %mrgnsb_cntr+1
endm
;;/* get the absolute value of x */
MR_ABS macro r:req,x:req,n:=<MREAL_XDIM>
IF MREAL_&x&_flg AND MREAL_FLG_NAN
IF MREAL_ERROR_FOR_NAN_INPUT
.err <x is not a numeric value>
ENDIF
MR_RAW_SET_N r,NaN,,n
EXITM
ELSEIF MREAL_&x&_flg AND MREAL_FLG_ZERO
MR_SET_ZERO r,n
EXITM
ENDIF
MR_MOV r,x,n
MREAL_&r&_flg = MREAL_&r&_flg AND (NOT MREAL_FLG_SIGN)
endm
;;/* r = -x */
MR_NEG macro r:req,x:req,n:=<MREAL_XDIM>
IF MREAL_&x&_flg AND MREAL_FLG_NAN
IF MREAL_ERROR_FOR_NAN_INPUT
.err <x is not a numeric value>
ENDIF
MR_RAW_SET_N r,NaN,,n
EXITM
ELSEIF MREAL_&x&_flg AND MREAL_FLG_ZERO
MR_SET_ZERO r,n
EXITM
ENDIF
MR_MOV r,x,n
MREAL_&r&_flg = MREAL_&r&_flg XOR MREAL_FLG_SIGN
endm
;;/* r = sgn(y)*|x| */
MR_COPY_SIGN macro r:req,x:req,y:req,n:=<MREAL_XDIM>
IF MREAL_&x&_flg AND MREAL_FLG_NAN
IF MREAL_ERROR_FOR_NAN_INPUT
.err <x is not a numeric value>
ENDIF
MR_RAW_SET_N r,NaN,,n
EXITM
ELSEIF MREAL_&y&_flg AND MREAL_FLG_NAN
IF MREAL_ERROR_FOR_NAN_INPUT
.err <y is not a numeric value>
ENDIF
MR_RAW_SET_N r,NaN,,n
EXITM
ELSEIF MREAL_&x&_flg AND MREAL_FLG_ZERO
MR_SET_ZERO r,n
EXITM
ENDIF
MR_MOV r,x,n
MREAL_&r&_flg = (MREAL_&r&_flg AND (NOT MREAL_FLG_SIGN)) OR MREAL_&y&_flg AND MREAL_FLG_SIGN
endm
;;/* cosmetic: @CatStr() is used to get <-1> as result and not <4294967295> */
MR_IS_ZERO macro x:req
EXITM @CatStr(%(MREAL_&x&_flg AND MREAL_FLG_ZERO) NE 0)
endm
MR_IS_SIGN_MINUS macro x:req
EXITM @CatStr(%(MREAL_&x&_flg AND MREAL_FLG_SIGN) NE 0)
endm
MR_IS_NORMAL macro x:req
EXITM @CatStr(%(MREAL_&x&_flg AND MREAL_FLG_NO_MANTISSA_TEST) EQ 0)
endm