EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

calcmain.htm
Data
Data
Procedures
Absolute
Calculate
Compare
ConvertToDecimal
Deparent
DisplayDecimal
EchoExpression
FnAdd
FnCos
FnDivide
FnExp
FnFactorial
FnLg
FnLn
FnMinus
FnMultiply
FnPlus
FnPower
FnSin
FnSubtract
FnTan
MaximizeMantissa
MinimizeMantissa
Negate
NormalizeMantissa
Parse
ParseNumber
UniteExponent
ZeroExponent

This is an OS-independent module of EuroTool program EuroCalc.


      EUROASM CPU=X64
calcmain PROGRAM Format=COFF, Width=64
      %DROPMACRO *
      INCLUDEHEAD1 argument.htm
      INCLUDE1 stdcal64.htm, cpuext64.htm, cpuext.htm, status32.htm

N        STRUC    ; Structure which describes a number or a function.
.MAN0     D DWORD ; Lowest  third of the mantissa.
.MAN1     D DWORD ; Middle  third of the mantissa.
.MAN2     D DWORD ; Highest third of the mantissa.
.EXP      D DWORD ; Binary exponent.
        ENDSTRUC N

O        STRUC    ; Structure which describes a function or operation.
.Oper     D QWORD ; Operator or function in lower case, e.g. '!','+','-','*','/','^','sin','log' etc.
.Handler  D QWORD ; Pointer to the handler.
.OperSize D WORD  ; Number of characters in .Oper (1,2 or 3).
.OperId   D WORD  ; Identifier of the operation or function (1,2,3,,,).
.Priority D WORD  ; Base priority of the operation, not influenced yet by parenthesis.
.Arity    D WORD  ; 'U','B','R','0','1'  ; Unary/Binary/Reversed/0/1 operand.
         ENDSTRUC O
Calculated numbers and functions in this program are represented by a 128-bit structure named N. It can be mentally visualized as a 128 bit wide variable where bits 0..95 represent the 96-bit mantissa as a signed binary integer in the range 8000_0000_0000_0000_0000_0000h..7FFF_FFFF_FFFF_FFFF_FFFF_FFFFh, and bits 96..127 represent the 32-bit exponent as a signed binary integer in the range 8000_0003h..7FFF_FFFFh. Signum of the exponent is in bit 127, signum of mantissa, and thus the signum of the entire number value, is in bit 95.
The value of exponent 8000_0000h is special. The structure with this value in exponent field is not a number but a function identified by the value in bits 0..15. Priority of the function is in bits 16..31.
The value of exponent 8000_0001h and 8000_0002h are special, too. The structure with this value in exponent field represents not a number or a function, but a parenthesis.
Number Function|operation bit number 127 96 64 32 0 bit number 127 96 64 32 0 ┌───────────────────────┬───────────────────────┐ ┌───────────────────────┬───────────────────────┐ register │ HI │ LO │ register │ HI │ LO │ ├───────────┬───────────┼───────────┬───────────┤ ├───────────┬───────────┼───────────┬───────────┤ member │ .EXP │ .MAN2 │ .MAN1 │ .MAN0 │ member │ .EXP │ .MAN2 │ .MAN1 │ .MAN0 │ ├───────────┼───────────┼───────────┼───────────┤ ├───────────┼───────────┼───────────┼───────────┤ hexa value │xx xx xx xx│mm mm mm mm│mm mm mm mm│mm mm mm mm│ hexa value │80 00 00 00│00 00 00 00│00 00 00 00│pp pp ff ff│ └───────────┴───────────┴───────────┴───────────┘ └───────────┴───────────┴───────────┴───────────┘ Left parenthesis Right parenthesis bit number 127 96 64 32 0 bit number 127 96 64 32 0 ┌───────────────────────┬───────────────────────┐ ┌───────────────────────┬───────────────────────┐ register │ HI │ LO │ register │ HI │ LO │ ├───────────┬───────────┼───────────┬───────────┤ ├───────────┬───────────┼───────────┬───────────┤ member │ .EXP │ .MAN2 │ .MAN1 │ .MAN0 │ member │ .EXP │ .MAN2 │ .MAN1 │ .MAN0 │ ├───────────┼───────────┼───────────┼───────────┤ ├───────────┼───────────┼───────────┼───────────┤ hexa value │80 00 00 01│00 00 00 00│00 00 00 00│00 00 00 00│ hexa value │80 00 00 02│00 00 00 00│00 00 00 00│00 00 00 00│ └───────────┴───────────┴───────────┴───────────┘ └───────────┴───────────┴───────────┴───────────┘
Functions
ValueOperation OperatorArity PriorityExample
1 FnEul EUL Function Euler's number with 0 operand15eul = 2.718_281_828_459_045_235_360_288
2 FnPi PI Function Ludolf's number with 0 operand15pi = 3.141_592_653_589_793_238_462_644
3 FnPlus + Unary operation12+2 = 2
4 FnMinus - Unary operation12-2 = -2
5 FnFactorial ! Reversed operation143 ! = 6
6 FnAdd + Binary operation 22 + 3 = 5
7 FnSubtract - Binary operation 22 - 3 = -1
8 FnMultiply * Binary operation 42 * 3 = 6
9 FnDivide / Binary operation 43 / 2 = 1.5
10 FnPower ^ Binary operation 62 ^ 3 = 8
11 FnSin SIN Function sine with 1 operand10sin (pi / 6) = 0.5
12 FnCos COS Function cosine with 1 operand10cos (pi / 6) = 0.5
13 FnTan TAN Function tangent with 1 operand10tan (pi / 4) = 1
14 FnCot COT Function cotangent with 1 operand10cot (pi / 4) = 1
15 FnSec SEC Function secant with 1 operand10sec pi = -1
16 FnCsc CSC Function cosecant with 1 operand10csc (pi/2) = 1
17 FnExp EXP Function exponent with 1 operand10exp 1 = 2.718_281_828_459_045_235_360_288
18 FnLn LN Function natural logarithm with 1 operand10ln eul = 1
19 FnLg LG Function decimal logarithm with 1 operand10lg 100 = 2
Examples
Number AliasMantissaExponentN
0 0 * 2 ^ 0 0 0 0x0000_0000_0000_0000_0000_0000_0000_0000
12 12 * 2 ^ 0 12 0 0x0000_0000_0000_0000_0000_0000_0000_000C
0.25 1 * 2 ^(-2) 1 -2 0xFFFF_FFFE_0000_0000_0000_0000_0000_0001
-64 -64 * 2 ^ 0 -64 0 0x0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF_FFC0
-64 -1 * 2 ^ 6 -1 6 0x0000_0006_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF
+∞0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF * 2 ^ 0x7FFF_FFFF 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF0x7FFF_FFFF0x7FFF_FFFF_7FFF_FFFF_FFFF_FFFF_FFFF_FFFF
-∞0x8000_0000_0000_0000_0000_0000 * 2 ^ 0x7FFF_FFFF0x8000_0000_0000_0000_0000_00000x7FFF_FFFF0x7FFF_FFFF_8000_0000_0000_0000_0000_0000
+1/∞0x0000_0000_0000_0000_0000_0001 * 2 ^ 0x8000_00010x0000_0000_0000_0000_0000_00010x8000_00010x8000_0001_0000_0000_0000_0000_0000_0001
-1/∞0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF * 2 ^ 0x8000_00010x0000_0000_0000_0000_0000_00010x8000_00010x8000_0001_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF
Fn #12h 0x0000_0000_0000_0000_0000_0012 * 2 ^ 0x8000_00000x0000_0000_0000_0000_0000_00120x8000_00000x8000_0000_0000_0000_0000_0000_0000_0012
↑ Data
[.rodata]     ; Constant data.
EuroCalc::DB "EuroCalc",0
Version:: DB " version %^Date",0
 ALIGN OWORD  ; Precomputed numeric constants in N format.
Pi        DS N, .EXP=-93, .MAN2=0x6487ED51, .MAN1=0x10B4611A, .MAN0=0x626330F4 ;  3.1415926535897932384626433
HalfPi    DS N, .EXP=-94, .MAN2=0x6487ED51, .MAN1=0x10B4611A, .MAN0=0x626330F4 ;  PI / 2
TwoPi     DS N, .EXP=-92, .MAN2=0x6487ED51, .MAN1=0x10B4611A, .MAN0=0x626330F4 ;  PI * 2
Eul       DS N, .EXP=-93, .MAN2=0x56FC2A2C, .MAN1=0x515DA54D, .MAN0=0x57EE2AC1 ;  2.7182818284590452353602874
OneEulth  DS N, .EXP=-96, .MAN2=0x5E2D58D8, .MAN1=0xB3BCDF1A, .MAN0=0xBADEC72C ;  0.3678794411714423215955237
OneLn10th DS N, .EXP=-96, .MAN2=0x6F2DEC54, .MAN1=0x9B9438CA, .MAN0=0x9AADD4F0 ;  0.4342944819032518276511289
OneTenth  DS N, .EXP=-96, .MAN2=0x19999999, .MAN1=0x99999999, .MAN0=0x99999999 ;  0.1000000000000000000000000
Half      DS N, .EXP=-1,  .MAN2=0x00000000, .MAN1=0x00000000, .MAN0=0x00000001 ;  0.5000000000000000000000000
One       DS N, .EXP=-94, .MAN2=0x40000000, .MAN1=0x00000000, .MAN0=0x00000000 ;  1.0000000000000000000000000
Two       DS N, .EXP=0,   .MAN2=0x00000000, .MAN1=0x00000000, .MAN0=0x00000002 ;  2.0000000000000000000000000
Eight     DS N, .EXP=0,   .MAN2=0x00000000, .MAN1=0x00000000, .MAN0=0x00000008 ;  8.0000000000000000000000000
Ten       DS N, .EXP=0,   .MAN2=0x00000000, .MAN1=0x00000000, .MAN0=0x0000000A ; 10.0000000000000000000000000
Sixteen   DS N, .EXP=0,   .MAN2=0x00000000, .MAN1=0x00000000, .MAN0=0x00000010 ; 16.0000000000000000000000000

Dictionary::   ; Table of calculator functions.
 DS O, .Handler=FnEul,      .Oper='eul', .OperSize=3, .OperId=01, .Priority=15, .Arity='0'
 DS O, .Handler=FnPi,       .Oper='pi' , .OperSize=2, .OperId=02, .Priority=15, .Arity='0'
 DS O, .Handler=FnPlus,     .Oper='+'  , .OperSize=1, .OperId=03, .Priority=12, .Arity='U'
 DS O, .Handler=FnMinus,    .Oper='-'  , .OperSize=1, .OperId=04, .Priority=12, .Arity='U'
 DS O, .Handler=FnFactorial,.Oper='!'  , .OperSize=1, .OperId=05, .Priority=14, .Arity='R'
 DS O, .Handler=FnAdd,      .Oper='+'  , .OperSize=1, .OperId=06, .Priority=02, .Arity='B'
 DS O, .Handler=FnSubtract, .Oper='-'  , .OperSize=1, .OperId=07, .Priority=02, .Arity='B'
 DS O, .Handler=FnMultiply, .Oper='*'  , .OperSize=1, .OperId=08, .Priority=04, .Arity='B'
 DS O, .Handler=FnDivide,   .Oper='/'  , .OperSize=1, .OperId=09, .Priority=04, .Arity='B'
 DS O, .Handler=FnPower,    .Oper='^'  , .OperSize=1, .OperId=10, .Priority=06, .Arity='B'
 DS O, .Handler=FnSin,      .Oper='sin', .OperSize=3, .OperId=11, .Priority=10, .Arity='1'
 DS O, .Handler=FnCos,      .Oper='cos', .OperSize=3, .OperId=12, .Priority=10, .Arity='1'
 DS O, .Handler=FnTan,      .Oper='tan', .OperSize=3, .OperId=13, .Priority=10, .Arity='1'
 DS O, .Handler=FnCot,      .Oper='cot', .OperSize=3, .OperId=14, .Priority=10, .Arity='1'
 DS O, .Handler=FnSec,      .Oper='sec', .OperSize=3, .OperId=15, .Priority=10, .Arity='1'
 DS O, .Handler=FnCsc,      .Oper='csc', .OperSize=3, .OperId=16, .Priority=10, .Arity='1'
 DS O, .Handler=FnExp,      .Oper='exp', .OperSize=3, .OperId=17, .Priority=10, .Arity='1'
 DS O, .Handler=FnLn,       .Oper='ln' , .OperSize=2, .OperId=18, .Priority=10, .Arity='1'
 DS O, .Handler=FnLg,       .Oper='lg' , .OperSize=2, .OperId=19, .Priority=10, .Arity='1'
DictionaryEnd:

TitleBtns:: DB 0,\          ; Labels on the buttons.
 "Clr",0,\                  ; Clear.
 "Bs",0, \                  ; Backspace.
 "^",0,  \                  ; Power.
 "/",0,  \
 "*",0,  \
 "-",0,  \
 "LN",0, \
 "LG",0, \
 "D",0,  \
 "E",0,  \
 "F",0,  \
 "+",0,  \
 "EXP",0,\
 "!",0,  \
 "A",0,  \
 "B",0,  \
 "C",0,  \
 "EUL",0,\
 "SIN",0,\
 "SEC",0,\
 "7",0,  \
 "8",0,  \
 "9",0,  \
 "PI",0, \
 "COS",0,\
 "CSC",0,\
 "4",0,  \
 "5",0,  \
 "6",0,  \
 "(",0,  \
 "TAN",0,\
 "COT",0,\
 "1",0,  \
 "2",0,  \
 "3",0,  \
 ")",0,  \
 "0y",0, \
 "0o",0, \
 "0x",0, \
 "0",0,  \
 ".",0,  \
 "=",0,  \
  0
TitleBtnsEnd::

[.bss]
               DS N       ; Reserve.
Pbuffer::      DS 640 * N ; Array of N-records, including records with parenthesis.
Nbuffer::      DS 640 * N ; Array of N-records, parenthesis removed, Fn0 replaced.
InpBuffer::    DB 640 * B ; Input expression, zero terminated.
OutBuffer::    DB 640 * B ; Output buffer for the result number.
PbufferEnd::   DQ QWORD   ; Pointer behind the last valid N-record.
NbufferEnd::   DQ QWORD   ; Pointer behind the last valid N-record. Decreased in Calculate.
ArgCount::     DQ QWORD   ; Number of arguments.
[.text]
Parse
PROC Parse reads the input expression, translates numbers, functions, parenthesis to structures N, stores them to RDI one after another.
Input
RSI is pointer to the ASCIIZ string with the expression which is calculated, e.g. (12h+0x34) * 2.
RDI is pointer to the buffer where N-records will be written.
Output
CF=0, RDI= position in OutputNbuffer after the last record.
Error
CF=1,
RSI= position in input expression where the error occured.
RDI= position in output Nbuffer after the last record.
Clobbers
RAX,RBX,RCX,RDX,R8,R9,R10,R11,R12,R13
Parse:: PROC
.AfterBegin:                 ; Expected: End, LeftParent, Unary, Number, Fn0, Fn1.
     LODSB
     CMP AL,0
     JE .End:
     CMP AL,'='
     JE .End:
     CMP AL,13
     JE .End:
     CMP AL,' '
     JE .AfterBegin:
     CMP AL,'('
     JE .StoreLeftParent:
     CMP AL,'-'
     JE .StoreUnary:
     CMP AL,'+'
     JE .StoreUnary:
     CMP AL,'0'
     JB .StoreFn:
     CMP AL,'9'
     JNA .StoreNumber:
     JMP .StoreFn:

.AfterUnary:                 ; Expected: LeftParent, Number, Fn0, Fn1.
     LODSB
     CMP AL,' '
     JE .AfterUnary:
     CMP AL,'('
     JE .StoreLeftParent:
     CMP AL,'0'
     JB .AU5:
     CMP AL,'9'
     JNA .StoreNumber:
.AU5:JMP .StoreFn:

.AfterBinary:                ; Expected: LeftParent, Number, Fn0, Fn1.
     LODSB
     CMP AL,' '
     JE .AfterBinary:
     CMP AL,'('
     JE .StoreLeftParent:
     CMP AL,'0'
     JB .AB5:
     CMP AL,'9'
     JBE .StoreNumber:
.AB5:JMP .StoreFn:

.AfterReversed:              ; Expected: End, RightParent, Reversed, Binary.
.AfterNumber:                ; Expected: End, RightParent, Reversed, Binary.
     LODSB
     CMP AL,0
     JE .End:
     CMP AL,13
     JE .End:
     CMP AL,10
     JE .End:
     CMP AL,'='
     JE .End:
     CMP AL,' '
     JE .AfterNumber:
     CMP AL,')'
     JE .StoreRightParent:
     CMP AL,'!'
     JE .StoreReversed:
     JMP .StoreBinary:

.AfterFn1:                   ; Expected: LeftParent, Unary, Number, Fn0.
     LODSB
     CMP AL,' '
     JE .AfterFn1:
     CMP AL,'('
     JE .StoreLeftParent:
     CMP AL,'-'
     JE .StoreUnary:
     CMP AL,'+'
     JE .StoreUnary:
     CMP AL,'0'
     JB .Err:
     CMP AL,'9'
     JA .StoreFn0:
     JMP .StoreNumber:

.StoreLeftParent:
     XOR EAX,EAX
     STOSQ
     MOV EAX,0x80000001
     SHL RAX,32
     STOSQ
     JMP .AfterBegin:

.StoreRightParent:
     XOR EAX,EAX
     STOSQ
     MOV EAX,0x80000002
     SHL RAX,32
     STOSQ
     JMP .AfterNumber:

.StoreNumber:
     DEC RSI
     PUSH RDI
       Invoke ParseNumber, RSI
     POP RDI
     MOV RAX,R8
     STOSQ
     MOV RAX,R9
     STOSQ
     JMP .AfterNumber:

.StoreReversed:              ; Reversed operator (!) is expected in AL.
     LEA RBX,[Dictionary]
     LEA RCX,[DictionaryEnd]
     SUB RBX,SIZE# O
.SR1:ADD RBX,SIZE# O
     CMP RBX,RCX
     JAE .Err:
     CMPB [RBX+O.Arity],'R'
     JNE .SR1:
     CMP [RBX+O.Oper],AL
     JNE .SR1:
     MOVZX EAX,[RBX+O.Priority]
     SHL EAX,16
     MOV AX,[RBX+O.OperId]
     STOSQ
     XOR EAX,EAX
     STC
     RCR RAX,1
     STOSQ
     JMP .AfterReversed:

.StoreUnary:                 ; Unary operator Plus or Minus is expected in AL.
     LEA RBX,[Dictionary]
     SUB RBX,SIZE# O
.SU1:ADD RBX,SIZE# O
     LEA RCX,[DictionaryEnd]
     CMP RBX,RCX
     JAE .Err:
     CMPB [RBX+O.Arity],'U'
     JNE .SU1:
     CMP [RBX+O.Oper],AL
     JNE .SU1:
     MOVZX EAX,[RBX+O.Priority]
     SHL EAX,16
     MOV AX,[RBX+O.OperId]
     STOSQ
     XOR EAX,EAX
     STC
     RCR RAX,1
     STOSQ
     JMP .AfterUnary:

.StoreBinary:                ; Binary operator is expected in AL.
     LEA RBX,[Dictionary]
     SUB RBX,SIZE# O
.SB1:ADD RBX,SIZE# O
     LEA RCX,[DictionaryEnd]
     CMP RBX,RCX
     JAE .Err:
     CMPB [RBX+O.Arity],'B'
     JNE .SB1:
     CMP [RBX+O.Oper],AL
     JNE .SB1:
     MOVZX EAX,[RBX+O.Priority]
     SHL EAX,16
     MOV AX,[RBX+O.OperId]
     STOSQ
     XOR EAX,EAX
     STC
     RCR RAX,1
     STOSQ
     JMP .AfterBinary:

.StoreFn0:
     DEC RSI                 ; Function name PI or EUL is expected at RSI. Anything else is error.
     MOV EAX,0x2020_2020
     OR EAX,[RSI]
     CMP AX,'pi'
     JNE .F0:
     ADD RSI,2
     MOV RAX,[Pi+0]
     STOSQ
     MOV RAX,[Pi+8]
     STOSQ
     JMP .AfterNumber:
.F0: CMP AX,'eu'
     JNE .Err:
     SHR EAX,16
     CMP AL,'l'
     JNE .Err:
     ADD RSI,3
     MOV RAX,[Eul+0]
     STOSQ
     MOV RAX,[Eul+8]
     STOSQ
     JMP .AfterNumber:

.StoreFn:
     DEC RSI                 ; Function name is expected at RSI. Anything else is error.
     LEA RBX,[Dictionary]
     SUB RBX,SIZE# O
.SF1:ADD RBX,SIZE# O
     LEA RCX,[DictionaryEnd]
     CMP RBX,RCX
     JAE .Err:
     MOV AL,[RBX+O.Arity]
     CMP AL,'1'
     JE .SF3:
     CMP AL,'0'
     JNE .SF1:
.SF3:MOV RAX,0x2020_2020_2020_2020
     OR RAX,[RSI]            ; Convert to lower case.
     MOVZX RCX,[RBX+O.OperSize]
     MOV EDX,ECX
     LEA ECX,[8*ECX]
     NEG ECX
     ADD ECX,64
     SHL RAX,CL
     SHR RAX,CL
     CMP RAX,[RBX+O.Oper]
     JNE .SF1:
     MOVZX EAX,[RBX+O.Priority]
     SHL EAX,16
     MOV AX,[RBX+O.OperId]
     STOSQ
     XOR EAX,EAX
     STC
     RCR RAX,1
     STOSQ
     ADD RSI,RDX
     CMPB [RBX+O.Arity],'0'
     JE .AfterNumber:
     JMP .AfterFn1:
.Err:STC
.End:RET
  ENDPROC Parse
ParseNumber NotationPtr
Load the input number to R9:R8 in N format.
The number can be in the following notations:
  1. Integer numbers
    • Decimal, e.g. 12_345
    • Decimal postfixed with dimension D,K,M,G,T,P, e.g. 12_345k
    • Decimal prefixed with 0N., e.g. 0n12_345
    • Hexadecimal postfixed with H, e.g. 1234_5678_9ABCh
    • Hexadecimal prefixed with 0X, e.g. 0x1234_5678_9ABC
    • Octal postfixed with Q, e.g. 123_456q
    • Octal prefixed with 0O, e.g. 0o123_456
    • Binary postfixed with B, e.g. 0101_0101b
    • Binary prefixed with 0Y, e.g. 0y0101_0101
  2. Floating-point numbers
    • FP numbers have one decimal point ., they may be in decimal format only, e.g. 123.45
    • They can be postfixed with E immediately followed with signed decadic exponent of 10, e.g. 123.45E5 or 123E-3.

Parsing algorithmus can distinguish between 123E4h (hexadecimal number 0x123E4) and 123E4 (decimal number 123*104=1230000).

The number format of EuroCalc is compatible with EuroAssembler but is not limited to 63 bits.
Input
NotationPtr is pointer at the beginning of number notation. It must point to a decimal digit.
Output
R9:R8 is the parsed number in N-format.
RSI points at the end of valid number notation.
Clobbers
RAX,RBX,RCX,RDX,R10,R11,R12,R13
ParseNumber:: Procedure NotationPtr
MultiplierHI LocalVar
MultiplierLO LocalVar
HighestPtr   LocalVar
HighestProc  LocalVar
    ClearLocalVar
    INCB [%MultiplierLO]     ; Default multiplier is 1.
    XOR R8,R8
    XOR R9,R9
    RstSt [Status::],ArgPostfix
    MOV RSI,[%NotationPtr]
    LODSB
    CMP AL,'0'
    JNE .NoPrefix:
    LODSB
    OR AL,0x20               ; Convert to lower case if it were part of prefix 'N','X','O','Y'.
    Dispatch AL,'n','x','o','y'
    JMP .NoPrefix:
.n: JMP .LoadDecimal:
.x: JMP .LoadHexa:
.o: JMP .LoadOctal:
.y: JMP .LoadBinary:
.NoPrefix: ; Radix may be specified by postfix 'H','Q','B','E' or by decimal postfix 'D','K','M','G','T','P'.
           ; We will parse and store the highest pointer together with its procedure (.LoadDecimal, .LoadOctal etc).
   ; First assume decimal format (%HighestProc=.LoadDecimal).
    MOV RSI,[%NotationPtr]
.TryDecimal:
    LODSB
    CMP AL,0
    JE .BidDecimal:
    CMP AL,'_'
    JE .TryDecimal:
    CMP AL,'0'
    JB .TestDecimal:
    CMP AL,'9'
    JBE .TryDecimal:
.TestDecimal:   ; First non-digit character after decimal digits.
    OR AL,0x20  ; Assume it's a decimal postfix, convert it to lower case 'd','k','m','g','t','p' or 'e'.
    CMP AL,'e'
    JE .NotDecimal:
    Dispatch AL,'d','k','m','g','t','p'
    DEC RSI
    JMP .BidDecimal:
.d: MOV EAX,1
    JMP .Exponent10:
.k: MOV EAX,1024
    JMP .Exponent10:
.m: MOV EAX,1_048_576
    JMP .Exponent10:
.g: MOV EAX,1_073_741_824
    JMP .Exponent10:
.t: MOV RAX,1_099_511_627_776
    JMP .Exponent10:
.p: MOV RAX,1_125_899_906_842_624
.Exponent10:
    MOV [%MultiplierLO],RAX
    SetSt [Status::],ArgPostfix
.BidDecimal:                 ; End of decimal format.
    MOV [%HighestPtr],RSI
    LEA RAX,[.LoadDecimal]
    MOV [%HighestProc],RAX
.NotDecimal:
    MOV RSI,[%NotationPtr]
    XOR ECX,ECX              ; RCX is nonzero when decimal point occured.
.TryFP:
    LODSB
    CMP AL,0
    JE .BidFP:
    CMP AL,'_'
    JE .TryFP:
    CMP AL,'.'
    JNE .TP:
    DEC RCX
    JMP .TryFP:
.TP:CMP AL,'0'
    JB .TestFP:
    CMP AL,'9'
    JBE .TryFP:
.TestFP:
    CMP AL,'E'               ; It should be 'E' or 'e', otherwise it's not FP when RCX=0.
    JE .ContFP:
    CMP AL,'e'
    JE .ContFP:
    TEST RCX
    JNZ .BidFP:
.ContFP:
    LODSB
    CMP AL,'-'
    JE .SignFP:
    CMP AL,'+'
    JNE .NoSignFP:
.SignFP:
    LODSB
.NoSignFP:
    CMP AL,'0'
    JB .BidFP:
    CMP AL,'9'
    JBE .SignFP:
.BidFP:
    DEC RSI
    CMP RSI,[%HighestPtr]
    JBE .NotFP:
    LEA RAX,[.LoadFP]
    MOV [%HighestProc],RAX
.NotFP:
    MOV RSI,[%NotationPtr]
.TryHexa:
    LODSB
    CMP AL,'_'
    JE .TryHexa:
    CMP AL,'0'
    JB .TestHexa:
    CMP AL,'9'
    JBE .TryHexa:
    CMP AL,'A'
    JB .TestHexa:
    CMP AL,'F'
    JBE .TryHexa:
    CMP AL,'a'
    JB .TestHexa:
    CMP AL,'f'
    JBE .TryHexa:
.TestHexa:
    OR AL,0x20               ; Assume hexa postfix 'H', convert it to lower case.
    CMP AL,'h'
    JNE .NotHexa:
    CMP RSI,[%HighestPtr]
    JB .NotHexa:
    SetSt [Status::],ArgPostfix
    LEA RAX,[.LoadHexa]
    MOV [%HighestProc],RAX
.NotHexa:
    MOV RSI,[%NotationPtr]
.TryOctal:
    LODSB
    CMP AL,'_'
    JE .TryOctal:
    CMP AL,'0'
    JB .TestOctal:
    CMP AL,'7'
    JBE .TryOctal:
.TestOctal:
    OR AL,0x20               ; Assume octal postfix 'Q', convert it to lower case.
    CMP AL,'q'
    JNE .NotOctal:
    CMP RSI,[%HighestPtr]
    JB .NotOctal:
    SetSt [Status::],ArgPostfix
    LEA RAX,[.LoadOctal]
    MOV [%HighestProc],RAX
.NotOctal:
    MOV RSI,[%NotationPtr]
.TryBinary:
    LODSB
    CMP AL,'_'
    JE .TryBinary:
    CMP AL,'0'
    JB .TestBinary:
    CMP AL,'1'
    JBE .TryBinary:
.TestBinary:
    OR AL,0x20               ; Assume binary postfix 'B', convert it to lower case.
    CMP AL,'b'
    JNE .NotBinary:
    SetSt [Status::],ArgPostfix
    CMP RSI,[%HighestPtr]
    JB .NotBinary:
    LEA RAX,[.LoadBinary]
    MOV [%HighestProc],RAX
.NotBinary:
    MOV RAX,[%HighestProc]
    MOV RSI,[%NotationPtr]
    JMP RAX
.LoadDecimal:
     XOR EAX,EAX
     LODSB
     CMP AL,0
     JE .Multiplier:
     CMP AL,'_'
     JE .LoadDecimal:
     SUB AL,'0'
     JB .Multiplier:
     CMP AL,9
     JA .Multiplier:
     PUSH RAX
       Invoke FnMultiply,R8,R9,[Ten+0],[Ten+8]
     POP R10
     XOR R11,R11
     Invoke FnAdd,R8,R9,R10,R11
     JMP .LoadDecimal:
.Multiplier:
     Invoke FnMultiply,R8,R9,[%MultiplierLO],[%MultiplierHI]
     JMP .End:
.LoadHexa:
     XOR EAX,EAX
     LODSB
     CMP AL,'_'
     JE .LoadHexa:
     SUB AL,'0'
     JB .End:
     CMP AL,9
     JBE .Hex:
     SUB AL,7
     CMP AL,10
     JB .End:
     CMP AL,15
     JB  .Hex:
     SUB AL,'a'-'A'
     CMP AL,10
     JB .End:
     CMP AL,15
     JA .End:
.Hex:
     PUSH RAX
      Invoke FnMultiply,R8,R9,[Sixteen+0],[Sixteen+8]
     POP R10
     XOR R11,R11
     Invoke FnAdd,R8,R9,R10,R11
     JMP .LoadHexa:
.LoadOctal:
     XOR EAX,EAX
     LODSB
     CMP AL,'_'
     JE .LoadOctal:
     SUB AL,'0'
     JB .End:
     CMP AL,7
     JA .End:
     PUSH RAX
      Invoke FnMultiply,R8,R9,[Eight+0],[Eight+8]
     POP R10
     XOR R11,R11
     Invoke FnAdd,R8,R9,R10,R11
     JMP .LoadOctal:
.LoadBinary:
     XOR EAX,EAX
     LODSB
     CMP AL,'_'
     JE .LoadBinary:
     SUB AL,'0'
     JB .End:
     CMP AL,1
     JA .End:
     PUSH RAX
      Invoke FnMultiply,R8,R9,[Two+0],[Two+8]
     POP R10
     XOR R11,R11
     Invoke FnAdd,R8,R9,R10,R11
     JMP .LoadBinary:
.LoadFP:
     XOR ECX,ECX     ; RCX is the decadic exponent.
.FP1:XOR EAX,EAX
     LODSB
     CMP AL,0
     JE .FP5:
     CMP AL,'_'
     JE .FP1:
     CMP AL,'.'
     JNE .FP2:
     TEST RCX
     JS .End:      ; Decimal point for the 2nd time - error.
     DEC RCX       ; RCX is below zero - decimal point occured.
     JMP .FP1:
.FP2:SUB AL,'0'
     JB .FP4:
     CMP AL,9
     JA .FP4:
     TEST RCX      ; Mantissa digit occured. If behind the decimal point, decrement RCX.
     JZ .FP3:      ; Decimal point didn't occured yet, keep RCX=0.
     DEC RCX       ; Otherwise decrement RCX for each digit in fraction.
.FP3:PUSH RAX,RCX  ; Count the digit.
       Invoke FnMultiply,R8,R9,[Ten+0],[Ten+8]
     POP RCX,R10
     XOR R11,R11
     PUSH RCX
       Invoke FnAdd,R8,R9,R10,R11
     POP RCX
     JMP .FP1:
.FP4:ADD AL,'0'    ; Rollback. Mantissa digits ended. AL should be 'E', otherwise FP number ended.
     TEST RCX      ; Test if decimal digit occured.
     JZ .FP6:
.FP5:INC RCX
     JZ .FP6:
     PUSH RAX,RCX  ; RCX is now the negative exponent of 10.
       Invoke FnMultiply,R8,R9,[OneTenth+0],[OneTenth+8]
     POP RCX,RAX
     JMP .FP5:
.FP6:; Decimal point is now solved.
     OR AL,0x20    ; Expected 'e' or 'E'.
     CMP AL,'e'
     JNE .End:
     LodD RSI      ; Signed decadic exponent expected after 'E'.
     INC RSI
     TEST RAX
     JZ .End:
     MOV RDX,RAX
     SAR RDX,32
     JZ .FP8:
     INC RDX
     JZ .FP8:
     DEC RSI       ; Make an error, exponent is too big.
.FP8:TEST RAX
     JZ .End:
     JS .FP9:
     PUSH RAX
      Invoke FnMultiply,R8,R9,[Ten+0],[Ten+8]
     POP RAX
     DEC RAX
     JMP .FP8:
.FP9:PUSH RAX
       Invoke FnMultiply,R8,R9,[OneTenth+0],[OneTenth+8]
     POP RAX
     INC RAX
     JMP .FP8:
.End:JSt [Status::],ArgPostfix,.90:
     DEC RSI
.90:EndProcedure ParseNumber
EchoExpression
PROC EchoExpression prepares string which repeats the parsed input expression.
Input
RSI is pointer to Pbuffer with N-records including parenthesis.
RDX= is pointer behind the last record in Pbuffer.
RDI= is pointer to the buffer for the expression.
Output
The output buffer is filled and zero terminated.
Clobbers
EchoExpression:: PROC
.10:CMP RSI,RDX
    JNB .90:
    LODSQ
    MOV R8,RAX
    LODSQ
    MOV R9,RAX
    SHR RAX,32
    CMP EAX,0x8000_0001
    JNE .20:
    MOV AL,'('
    STOSB
    JMP .10:
.20:CMP EAX,0x8000_0002
    JNE .30:
    MOV AL,')'
    STOSB
    JMP .10:
.30:CMP EAX,0x8000_0000
    JE .40:
    PUSH RDX,RSI
       Invoke DisplayDecimal,R8,R9,RDI
    POP RSI,RDX
    DEC RDI                  ; Rollback at the terminating zero.
    JMP .10:
.40:LEA RBX,[Dictionary]
    MOVZX ECX,R8W
    DEC ECX
    LEA RCX,[2*RCX+RCX]
    SAL ECX,3
    MOV  RAX,[RBX+RCX+O.Oper]
    MOVZX CX,[RBX+RCX+O.OperSize]
.50:STOSB
    SHR RAX,8
    LOOP .50:
    JMP .10:
.90:MOV EAX,0x0A0D3D20
    STOSD
    XOR EAX,EAX
    STOSB
    RET
   ENDP EchoExpression
Deparent
PROC Deparent retrieves input buffer with N-records including parenthesis and rewrites it to output buffer omitting parenthesis N-records. Instead of parenthesis record it increases priority of all functions and operations between those parenthesis.
The procedure also replaces functions PI and EUL with the corresponding number.
Input
RSI is pointer to the first N-record in input Pbuffer.
RDX is pointer behing the last record in the input Pbuffer.
RDI is pointer to the output buffer where N-records will be written.
Output
CF=0, RDI= position in output Nbuffer after the last record.
Error
CF=1 if the parenthesis were unbalanced.
Clobbers
RAX,RBX,RSI
Deparent:: PROC
    XOR EBX,EBX                ; Priority.
    JMPS .20:
.10:MOVSQ
    MOVSQ
.20:CMP RSI,RDX
    JNC .80:
    MOV RAX,[RSI+8]
    CMP EAX,0
    JNE .10:
    SHR RAX,32
    CMP EAX,0x80000002
    JE .50:
    CMP EAX,0x80000001
    JE .60:
    CMP EAX,0x80000000
    JNE .10:
    ADD [RSI+0],EBX             ; Modify the priority of function|operation.
    CMPW [RSI+0],1              ; Function EUL?
    JNE .40:
    MOV RAX,[Eul+0]
    STOSQ
    MOV RAX,[Eul+8]
    STOSQ
.30:ADD RSI,2*8
    JMP .20:
.40:CMPW [RSI+0],2              ; Function PI?
    JNE .10:
    MOV RAX,[Pi+0]
    STOSQ
    MOV RAX,[Pi+8]
    STOSQ
    JMP .30:
.50:TEST EBX                    ; Right parenthesis.
    STC
    JZ .90:
    SUB EBX,0x0010_0000
    JMP .30:
.60:ADD EBX,0x0010_0000         ; Left parenthesis.
    JMP .30:
.80:TEST EBX
    JZ .90:
    STC
.90:RET
   ENDP Deparent
Calculate
Proc Calculate computes an expression from N-records in the Nbuffer up to NbufferEnd. In the end there will be only one N-record left with the resulting number.
Input
Nbuffer is the buffer with N-records.
[NbufferEnd] is pointer behind the last N-record in the Nbuffer.
Output
CF=0, R9:R8 is the result.
Error
CF=1
Clobbers
all
Calculate:: PROC
.00:XOR ECX,ECX                 ; Highest priority so far.
    LEA RSI,[Nbuffer]
    LEA RAX,[RSI+SIZE# N]
    CMP RAX,[NbufferEnd]
    JAE .80:                    ; Calculation done, only one N remains on Nbuffer.
    SUB RSI,SIZE# N
.10:ADD RSI,SIZE# N
    CMP RSI,[NbufferEnd]
    JAE .20:
    CMP [RSI+N.EXP],0x80000000  ; Is it number or function?
    JNE .10:                    ; Searching for a function only.
    MOVZXW EAX,[RSI+N.MAN0+2]   ; Priority of this function.
    CMP EAX,ECX
    JBE .10:
    MOV ECX,EAX
    MOV RBX,RSI                 ; RBX is pointer to the best function so far.
    JMP .10:
.20:MOVZXW EDX,[RBX+N.MAN0+0]   ; RBX is pointer to the function with highest priority. EDX=O.OperId
    SAL EDX,3
    LEA RDI,[Dictionary+2*RDX+RDX-SIZE#O] ; RDI points to a dictionary line.
    LEA RCX,[RBX-SIZE#N]        ; RCX points at preceding N on Nbuffer (perhaps the left operand).
    MOV R8,[RCX+0]
    MOV R9,[RCX+8]              ; R9:R8 is the potential preceding operand.
    LEA RDX,[RBX+SIZE#N]        ; RDX points at subsequent N on Nbuffer (perhaps the right operand).
    MOV R10,[RDX+0]
    MOV R11,[RDX+8]             ; R11:R10 is the potential following operand.
    MOV R15,[RDI+O.Handler]
    MOVB AL,[RDI+O.Arity]       ; Arity in AL decides of handler's arguments.
    Dispatch AL,'U','B','R','1','0'
.0: Invoke R15                  ; Function without operand (eul, pi).
    MOV [RBX+0],R8
    MOV [RBX+8],R9
    JMP .00:
.1:                             ; Function with one operand (sin, exp etc).
.U: PUSH RBX
      Invoke R15,R10,R11        ; Unary function (plus, minus).
    POP RBX
    JC .90:
    MOV [RBX+0],R8
    MOV [RBX+8],R9
    LEA RSI,[RBX+2*SIZE# N]
    LEA RDI,[RBX+1*SIZE# N]
    MOV RCX,[NbufferEnd]
    SUB RCX,RBX
    SUB ECX,2*SIZE# N
    REP MOVSB
    MOV [NbufferEnd],RDI
    JMP .00:
.B: PUSH RBX
      Invoke R15,R8,R9,R10,R11  ; Binary function (addition, multiplication etc).
    POP RBX
    JC .90:
    MOV [RBX-SIZE# N +0],R8
    MOV [RBX-SIZE# N +8],R9
    LEA RSI,[RBX+2*SIZE# N]
    MOV RDI,RBX
    MOV RCX,[NbufferEnd]
    SUB RCX,RBX
    SUB ECX,2*SIZE# N
    REP MOVSB
    MOV [NbufferEnd],RDI
    JMP .00:
.R: PUSH RBX
      Invoke R15,R8,R9          ; Reversed function (factorial).
    POP RBX
    JC .90:
    MOV [RBX-SIZE# N +0],R8
    MOV [RBX-SIZE# N +8],R9
    LEA RSI,[RBX+1*SIZE# N]
    MOV RDI,RBX
    MOV RCX,[NbufferEnd]
    SUB RCX,RBX
    SUB ECX,1*SIZE# N
    REP MOVSB
    MOV [NbufferEnd],RDI
    JMP .00:
.80:MOV R8,[RSI+0]
    MOV R9,[RSI+8]
.90:RET
    ENDP Calculate
FnPi
Store as Ludolf's number.
Input
-
Output
R9:R8 is the number PI.
Clobbers
-
FnPi Procedure
     MOV R8,[Pi+0]
     MOV R9,[Pi+8]
   EndProcedure FnPi
FnEul
Store as Euler's number.
Input
-
Output
R9:R8 is the number EUL.
Clobbers
-
FnEul Procedure
     MOV R8,[Eul+0]
     MOV R9,[Eul+8]
   EndProcedure FnEul
FnFactorial NumberLO, NumberHI
Calculate factorial of nonnegative integer number or of the nonnegative noninteger number rounded down to integer.
Input
NumberLO, NumberHI is the input number.
Output
R9:R8 is the factorial of Number.
CF=0
Clobbers
RAX,RBX,RCX,RDX,R10,R11,R12,R13,R14
FnFactorial:: Procedure NumberLO, NumberHI
PreviousHI  LocalVar
PreviousLO  LocalVar
FactorialHI LocalVar
FactorialLO LocalVar
      XOR EAX,EAX
      MOV [%FactorialHI],RAX
      MOV [%PreviousHI],RAX
      MOV AL,2
      MOV [%FactorialLO],RAX
      MOV [%PreviousLO],RAX       ; %Previous and %Factorial are 2.
      Invoke Compare,[%NumberLO],[%NumberHI],[Two+0],[Two+8]
      JBE .80:
.50:  MOV R10,[%PreviousLO]
      MOV R11,[%PreviousHI]
      INC R10
      MOV [%PreviousLO],R10
      MOV R8,[%FactorialLO]
      MOV R9,[%FactorialHI]
      Invoke FnMultiply,R8,R9,R10,R11
      MOV [%FactorialLO],R8
      MOV [%FactorialHI],R9
      Invoke Compare,[%PreviousLO],[%PreviousHI],[%NumberLO],[%NumberHI]
      JB .50:
.80:  MOV R8,[%FactorialLO]
      MOV R9,[%FactorialHI]
   EndProcedure FnFactorial
FnPlus NumberLO, NumberHI
Do nothing.
Input
Number is the input number in format N.
Output
R9:R8 is the result number, identical with the input number.
CF=0
Clobbers
-
FnPlus Procedure NumberLO, NumberHI
    MOV R8,[%NumberLO]
    MOV R9,[%NumberHI]
  EndProcedure FnPlus
FnMinus NumberLO, NumberHI
Invert the number.
Input
Number is the input number in format N.
Output
R9:R8 is the result number, inverted value of the input number.
CF=0
Clobbers
RAX
FnMinus Procedure NumberLO, NumberHI
    MOV R8,[%NumberLO]
    MOV R9,[%NumberHI]
    CALL Negate:
  EndProcedure  FnMinus
FnAdd Addend1LO, Addend1HI, Addent2LO, Addend2HI
Add two numbers.
N.EXP of both numbers will be united before addition of N.MAN.
Input
Addend1 is the first addend in format N.
Addend2 is the second addend in format N.
Output
R9:R8 is the result number.
CF=0
Clobbers
RAX,RCX,RDX,R10,R11
FnAdd:: Procedure Addend1LO, Addend1HI, Addend2LO, Addend2HI
     MOV R8,[%Addend1LO]
     MOV R9,[%Addend1HI]
     MOV R10,[%Addend2LO]
     MOV R11,[%Addend2HI]
     CALL UniteExponent
.10: MOV RAX,R8
     MOV RDX,R9
     MOV R12,R8
     MOV R13,R9
     ADD R8,R10
     ADC R9D,R11D
     JO .20:
     SAR RDX,32
     SAL RDX,32
     ADD R9,RDX
     JMP .90:
.20: ; Rollback: shift-right (decrease) MAN and increase EXP by 1.
     MOV R8,R12
     MOV R9,R13       ; Restore Addend1.
     MOV RDX,R9
     SHR RDX,32
     INC RDX
     SHL RDX,32
     SAR R9D,1
     RCR R8,1
     JNC .30:
.30: MOV R9D,R9D
     ADD R9,RDX
     MOV RAX,R11
     SHR RAX,32
     INC RAX
     SHL RAX,32
     SAR R11D,1
     RCR R10,1
     JNC .40:
.40: MOV R11D,R11D
     ADD R11,RAX
     JMP .10:
.90: CLC
    EndProcedure FnAdd
FnSubtract MinuendLO, MinuendHI, SubtrahendLO, SubtrahendHI
Subtract subtrahend from minuend.
N.EXP of both numbers will be united before subtraction of N.MAN.
Input
Minuhend is the number in format N to be subtracted from.
Subtrahend is the number in N format which will be subtracted.
Output
R9:R8 is the difference.
Clobbers
RAX,RCX,RDX,R10,R11
FnSubtract Procedure  MinuendLO, MinuendHI, SubtrahendLO, SubtrahendHI
     MOV R8,[%MinuendLO]
     MOV R9,[%MinuendHI]
     MOV R10,[%SubtrahendLO]
     MOV R11,[%SubtrahendHI]
     CALL UniteExponent
.10: MOV RAX,R8
     MOV RDX,R9
     SUB R8,R10
     SBB R9D,R11D
     JO .20:
     SAR RDX,32
     SAL RDX,32
     ADD R9,RDX
     JMP .90:
.20: ; Rollback; increase both EXP by 1, decrease MAN.
     MOV RAX,R9
     SAR R9D,1
     RCR R8,1
     JNC .30:
.30: MOV R9D,R9D
     SAR RAX,32
     INC RAX
     SAL RAX,32
     ADD R9,RAX
     MOV RAX,R11
     SAR R11D,1
     RCR R10,1
     JNC .40:
.40: MOV R11D,R11D
     SAR RAX,32
     INC RAX
     SAL RAX,32
     ADD R11,RAX
     JMP .10:
.90: CLC
   EndProcedure FnSubtract
FnMultiply Factor1LO, Factor1HI, Factor2LO, Factor2HI
Procedure FnMultiply multiplies two numbers.
Input
Factor1 the first factor in format N.
Factor2 is the second factor in format N.
Output
R9:R8 is the product in format N.
CF=0
Clobbers
RAX,RBX,RCX,RDX,R10,R11,R12,R13,R14
FnMultiply Procedure Factor1LO, Factor1HI, Factor2LO, Factor2HI
Signums  LocalVar
    XOR ECX,ECX    ; Negative values of both factors are converted to positive. The signs are kept in BH, BL.
    Invoke Absolute, [%Factor2LO],[%Factor2HI] ; Convert negative number to positive R9:R8 and set CF if it was negative.
    ADC CL,0
    MOV R10,R8
    MOV R11,R9
    Invoke Absolute, [%Factor1LO],[%Factor1HI]; Convert negative number to positive R9:R8 and set CF if it was negative.
    ADC CH,0
    MOV [%Signums],RCX
    XOR EBX,EBX    ; Prepare exponent of the product.
    XOR R14,R14    ; Prepare the result of mantissas multiplication to R14:R13:R12.
    MOV RAX,R10
    MUL R8
    MOV R12,RAX
    MOV R13,RDX
    MOV EAX,R11D
    MUL R8
    ADD R13,RAX
    ADC R14,RDX
    ADC R15,0
    MOV EAX,R9D
    MUL R10
    ADD R13,RAX
    ADC R14,RDX
    MOV EAX,R11D
    MOV EDX,R9D
    MUL RDX
    ADD R14,RAX
    JZ .40:
    BSR RCX,R14    ; R14 is nonzero.
    ADD CL,32+2
    MOV EBX,ECX    ; We need to shift MAN by ECX bits to the right.
    JMP .50:
.40:TEST R13
    JZ .70:
    BSR RCX,R13    ; R14:R13 is nonzero.
    SUB CL,32-2
    JNA .70:
    MOV EBX,ECX    ; We need to shift MAN by ECX bits to the right.
.50:SHR R14,1
    RCR R13,1
    RCR R12,1
    JNC .60:
.60:DEC ECX
    JNZ .50:
.70:MOV RAX,R9      ; Manissa of the product is in bits 0..95.
    SAR RAX,32
    MOV RDX,R11
    SAR RDX,32
    ADD RAX,RDX     ; Add exponents.
    ADD RAX,RBX     ; Add how many time was mantissa shifted to the right.
    SAL RAX,32
    MOV R8,R12
    MOV R9D,R13D
    ADD R9,RAX
    MOV RCX,[%Signums]
    XOR CL,CH
    JZ .90:
    CALL Negate
.90:CLC
   EndProcedure FnMultiply
FnDivide DividendLO, DividendHI, DivisorLO, DivisorHI
Procedure FnDivide divides two numbers.
Input
Dividend is the divided number in format N.
Divisor is the number by which will be Dividend divided in format N.
Output
R9:R8 is the quotient in format N.
CF=0
Error
CF=1 when divisor is 0. R9:R8 is undefined.
Clobbers
RAX,RBX,RCX,RDX,RSI,RDI,R10,R11,R12,R13,R14
FnDivide Procedure DividendLO, DividendHI, DivisorLO, DivisorHI
Signum       LocalVar  ; Zero if Quotient will be positive.
DividendNxHI LocalVar  ; Variables with Nx have exponent=0.
DividendNxLO LocalVar
DivisorNxHI  LocalVar
DivisorNxLO  LocalVar
QuotientNxHI LocalVar
QuotientNxLO LocalVar
    XOR ECX,ECX
    Invoke Absolute, [%DividendLO],[%DividendHI] ; Convert negative number to positive R9:R8 and set CF if it was negative.
    ADC CL,0
    MOV [%Signum],RCX
    CALL MaximizeMantissa    ; R9D:R8 od the dividend will be increased, EXP decreased.
    MOV [%DividendLO],R8
    MOV [%DividendHI],R9
    MOV R9D,R9D              ; Put zero to exponent.
    MOV [%DividendNxLO],R8
    MOV [%DividendNxHI],R9
    MOV EAX,R9D
    OR RAX,R8
    JZ .80:                  ; Dividend=0, return 0.
    XOR ECX,ECX              ; Negative values of both factors are converted to positive.
    Invoke Absolute, [%DivisorLO],[%DivisorHI] ; Convert negative number to positive R9:R8 and set CF if it was negative.
    ADC CL,0                 ; Result Signum is 0 or 1.
    XOR [%Signum],RCX
    CALL MaximizeMantissa
    MOV EAX,R9D
    OR RAX,R8
    STC
    JZ .90:                  ; Error when division by 0.
    MOV [%DivisorLO],R8
    MOV [%DivisorHI],R9
    MOV RCX,R9
    MOV EAX,ECX
    SAR RCX,32
.10:CMP RAX,[%DividendNxHI]
    JL .20:
    SHR EAX,1                ; Mantissa of divident (DividendNx) is below mantissa of divisor (DivisorNx).
    RCR R8,1                 ; Decrement mantissa of divisor
    INC RCX                  ;  and increment its exponent.
    JMP .10:
.20:SAL RCX,32
    ADD RAX,RCX
    MOV [%DivisorLO],R8
    MOV [%DivisorHI],RAX
    MOV EAX,EAX              ; Put zero to exponent.
    MOV [%DivisorNxLO],R8
    MOV [%DivisorNxHI],RAX
    MOV RSI,[One+0]
    MOV RDI,[One+8]
    MOV [%QuotientNxLO],RSI
    MOV [%QuotientNxHI],RDI
    MOV EDI,EDI         ; EDI:RSI keeps walking 1 which walks from bit 94 to 0.
.30:OR [%QuotientNxLO],RSI
    OR [%QuotientNxHI],RDI
    Invoke FnMultiply,[%QuotientNxLO],[%QuotientNxHI],[%DivisorNxLO],[%DivisorNxHI]
    Invoke Compare,R8,R9,[%DividendNxLO],[%DividendNxHI]
    JE .50:
    JB .40:                  ; Quotient is below, let it keep the walking1 and walk on.
    XOR [%QuotientNxLO],RSI  ; Quotient is above, remove walking1 EDI:RSI from quotient.
    XOR [%QuotientNxHI],RDI
.40:SHR RDI,1                ; Shift the walking 1 one position to the right.
    RCR RSI,1
    JNC .30:                 ; Repeat 95 times.
.50:MOV R8,[%QuotientNxLO]
    MOV R9,[%QuotientNxHI]
    MOV RAX,[%DividendHI]
    MOV RDX,[%DivisorHI]
    SAR RAX,32
    SAR RDX,32
    SUB RAX,RDX
    SAL RAX,32
    ADD R9,RAX
    TESTB [%Signum],1
    JZ .80:
    CALL Negate
.80:CLC
.90:EndProcedure FnDivide
FnSin AngleLO, AngleHI
Procedure FnSin computes sinus of an angle.
sin(x)=x^1/1! -x^3/3! +x^5/5! -x^7/7! +x^9/9! -x^11/11! +...
It adds members of Taylor series until the resulting sum does not differ from the previous one.
Input
AngleLO, AngleHI is the angle.
Output
R9:R8 is the sinus in format N.
CF=0
Clobbers
RAX,RBX,RCX,RDX,RSI,RDI,R10,R11,R12,R13,R14
FnSin:: Procedure AngleLO, AngleHI
Number       LocalVar   ; Ordinal member number 1, 3, 5, 7, 9,..
Signum       LocalVar   ; Nonzero for negative output.
PowerLO      LocalVar   ; Angle ^ Number.
PowerHI      LocalVar
FactHI       LocalVar   ; Number !
FactLO       LocalVar
ResultHI     LocalVar   ; Sum of members.
ResultLO     LocalVar
PrevResultLO LocalVar   ; Used for detection if the result does not change.
PrevResultHI LocalVar
    MOV R8,[%AngleLO]   ; Saturate Angle between 0 and 2*PI.
    MOV R9,[%AngleHI]
.10:BT R9,31
    JNC .20:
    Invoke FnAdd,R8,R9,[TwoPi+0],[TwoPi+8]       ; While Angle is negative.
    JMP .10:
.20:MOV [%AngleLO],R8
    MOV [%AngleHI],R9
    Invoke Compare, R8,R9,[TwoPi+0],[TwoPi+8]
    JB .30:
    Invoke FnSubtract,[%AngleLO],[%AngleHI],[TwoPi+0],[TwoPi+8] ; While Angle is above 2*PI.
    JMP .20:
.30:XOR ECX,ECX                                  ; Angle is between 0 and 2*PI.
    MOV [%Signum],RCX                            ; Sinus is positive when Angle 0..PI.
    Invoke Compare, [%AngleLO],[%AngleHI],[Pi+0],[Pi+8]
    JB  .40:
    XOR ECX,ECX                                  ; Otherwise Angle is between PI..2*PI.
    DEC RCX                                      ; Signum is negative.
    MOV [%Signum],RCX                            ; Result PI..2*PI is negative.
    Invoke FnSubtract,[%AngleLO],[%AngleHI],[Pi+0],[Pi+8]
    MOV [%AngleLO],R8
    MOV [%AngleHI],R9
.40:MOV R8,[%AngleLO]
    MOV R9,[%AngleHI]                            ; Angle is now between 0 and PI.
    Invoke Compare, R8,R9,[HalfPi+0],[HalfPi+8]
    JB .50:
    Invoke FnSubtract,[%AngleLO],[%AngleHI],[HalfPi+0],[HalfPi+8] ; Angle was between PI/2 and PI.
    Invoke FnSubtract,[HalfPi+0],[HalfPi+8],R8,R9 ; R9:R8 is now between 0 and PI/2. Angle is reversed.
    MOV [%AngleLO],R8
    MOV [%AngleHI],R9                            ; Angle is between 0 and PI/2.
.50:; Initialize temporary results.
    MOV R8,[%AngleLO]
    MOV R9,[%AngleHI]
    MOV [%ResultLO],R8
    MOV [%ResultHI],R9
    MOV [%PrevResultLO],R8
    MOV [%PrevResultHI],R9
    XOR EAX,EAX
    MOV [%FactHI],RAX
    INC EAX
    MOV [%FactLO],RAX
    MOV [%PowerLO],R8
    MOV [%PowerHI],R9
    MOV [%Number],RAX
.55:MOV R8,[%PowerLO]                  ; Compute %Power= %Power * %Angle * %Angle.
    MOV R9,[%PowerHI]
    Invoke FnMultiply,R8,R9,[%AngleLO],[%AngleHI]
    Invoke FnMultiply,R8,R9,[%AngleLO],[%AngleHI]
    MOV [%PowerLO],R8                  ; Angle^3, Angle^5, Angle^7 etc
    MOV [%PowerHI],R9
    MOV RSI,[%Number]                  ; Compute %Fact = %Number ! = %Fact * (%Number+1) * (%Number+2)
    XOR EDI,EDI
    INC RSI
    Invoke FnMultiply,[%FactLO],[%FactHI],RSI,RDI
    INC RSI
    MOV [%Number],RSI
    Invoke FnMultiply,R8,R9,RSI,RDI
    MOV [%FactLO],R8
    MOV [%FactHI],R9
    Invoke FnDivide,[%PowerLO],[%PowerHI],R8,R9    ; Compute %Power / %Factorial
    JC .90:
    MOV RCX,[%Number]                   ; Add or subtract the quotient R9:R8 to %Result.
    SHR RCX,2
    JC .60:
    Invoke FnAdd,[%ResultLO],[%ResultHI],R8,R9
    JMPS .70:
.60:Invoke FnSubtract,[%ResultLO],[%ResultHI],R8,R9
.70:MOV [%ResultLO],R8
    MOV [%ResultHI],R9
    PUSH R8,R9
    Invoke Compare,R8,R9,[%PrevResultLO],[%PrevResultHI]
    POP R9,R8
    MOV [%PrevResultLO],R8
    MOV [%PrevResultHI],R9
    JNE .55:                            ; Compute the next member if they differ.
    MOV R8,[%ResultLO]
    MOV R9,[%ResultHI]
    TESTB [%Signum],1
    JZ .85:
    CALL Negate
.85:CLC
.90:EndProcedure FnSin
FnCos AngleLO, AngleHI
Procedure FnCos computes cosinus of an angle.
cos(x)=sin(x+PI/2)
Input
AngleLO, AngleHI is the angle.
Output
R9:R8 is the sinus in format N.
CF=0
Clobbers
RAX,RBX,RCX,RDX,RSI,RDI,R10,R11,R12,R13,R14
FnCos Procedure AngleLO, AngleHI
    Invoke FnAdd,[%AngleLO],[%AngleHI],[HalfPi+0],[HalfPi+8]
    Invoke FnSin,R8,R9
   EndProcedure FnCos
FnTan AngleLO, AngleHI
Procedure FnTan computes tangent of an angle.
tan(x)=sin(x)/cos(x)
Input
AngleLO, AngleHI is the angle.
Output
R9:R8 is the tangent in format N.
Clobbers
RAX,RBX,RCX,RDX,RSI,RDI,R10,R11,R12,R13,R14
FnTan Procedure AngleLO, AngleHI
    Invoke FnCos,[%AngleLO],[%AngleHI]
    PUSH R8,R9
      Invoke FnSin,[%AngleLO],[%AngleHI]
    POP R11,R10
    Invoke FnDivide,R8,R9,R10,R11
   EndProcedure FnTan
FnCot AngleLO, AngleHI
Procedure FnCot computes cotangent of an angle.
cot(x)=cos(x)/sin(x)
Input
AngleLO, AngleHI is the angle.
Output
R9:R8 is the cotangent in format N.
Clobbers
RAX,RBX,RCX,RDX,RSI,RDI,R10,R11,R12,R13,R14
FnCot Procedure AngleLO, AngleHI
    Invoke FnSin,[%AngleLO],[%AngleHI]
    PUSH R8,R9
      Invoke FnCos,[%AngleLO],[%AngleHI]
    POP R11,R10
    Invoke FnDivide,R8,R9,R10,R11
   EndProcedure FnCot
FnSec AngleLO, AngleHI
Procedure FnSec computes secant of an angle.
sec(x)=1/cos(x)
Input
AngleLO, AngleHI is the angle.
Output
R9:R8 is the secant in format N.
Clobbers
RAX,RBX,RCX,RDX,RSI,RDI,R10,R11,R12,R13,R14
FnSec Procedure AngleLO, AngleHI
    Invoke FnCos,[%AngleLO],[%AngleHI]
    Invoke FnDivide,[One+0],[One+8],R8,R9
   EndProcedure FnSec
FnCsc AngleLO, AngleHI
Procedure FnCsc computes cosecant of an angle.
csc(x)=1/sin(x)
Input
AngleLO, AngleHI is the angle.
Output
R9:R8 is the cosecant in format N.
Clobbers
RAX,RBX,RCX,RDX,RSI,RDI,R10,R11,R12,R13,R14
FnCsc Procedure AngleLO, AngleHI
    Invoke FnSin,[%AngleLO],[%AngleHI]
    Invoke FnDivide,[One+0],[One+8],R8,R9
   EndProcedure FnCsc
FnExp NumberLO, NumberHI
Procedure FnExp computes euler's number to a positive number.
exp x = x^0/0! + x^1/1! + x^2/2! + x^3/3! + x^4/4! + ...
exp 0 = 1
exp 1 = EUL
exp 2 = EUL*EUL=7.389...
For simplicity it does not compute euler's number to negative numbers,
Input
NumberLO, NumberHI is the input number.
Output
R9:R8 is the EUL ^ Number.
CF=0
Clobbers
RAX,RBX,RCX,RDX,RSI,RDI,R10,R11,R12,R13,R14
FnExp:: Procedure NumberLO, NumberHI
OrderLO      LocalVar
OrderHI      LocalVar
PowerLO      LocalVar
PowerHI      LocalVar
FactLO       LocalVar
FactHI       LocalVar
ResultHI     LocalVar
ResultLO     LocalVar
PrevResultLO LocalVar
PrevResultHI LocalVar
    XOR EAX,EAX
    XOR EDX,EDX
    INC EAX
    MOV [%ResultLO],RAX ; Initialize Result to 1.
    MOV [%ResultHI],RDX
    INC EAX
    MOV [%FactLO],RAX   ; Initialize Fact to 2.
    MOV [%FactHI],RDX
    MOV [%OrderLO],RAX  ; Initialize Order to 2.
    MOV [%OrderHI],RDX
    MOV RAX,[%NumberLO]
    MOV RDX,[%NumberHI]
    BT RDX,31
    JC .90:
    MOV [%PowerLO],RAX  ; Initialize Power to 1*Number.
    MOV [%PowerHI],RDX
    Invoke FnAdd,RAX,RDX,[%ResultLO],[%ResultHI]
    MOV [%ResultLO],R8  ; Initialize Result to 1+Number.
    MOV [%ResultHI],R9
.30:; Calculate Power = Power * Number
    Invoke FnMultiply,[%PowerLO],[%PowerHI],[%NumberLO],[%NumberHI]
    MOV [%PowerLO],R8
    MOV [%PowerHI],R9 ; Power = Number ^ Order
    Invoke FnDivide,R8,R9,[%FactLO],[%FactHI]
    JC .90:
    Invoke FnAdd,[%ResultLO],[%ResultHI],R8,R9
    MOV [%ResultLO],R8
    MOV [%ResultHI],R9
    PUSH R8,R9
     Invoke Compare,R8,R9,[%PrevResultLO],[%PrevResultHI]
    POP R9,R8
    MOV [%PrevResultLO],R8
    MOV [%PrevResultHI],R9
    JE .80:
   ; Increment the next Order.  exp x = 1 + x + x^2/2! + x^3/3! + x^4/4! + ...
    MOV RAX,[%OrderLO]
    INC RAX
    JZ .80:
    MOV [%OrderLO],RAX
    ; Calculate Fact = Fact * Order
    MOV R8,[%FactLO]
    MOV R9,[%FactHI]
    Invoke FnMultiply, R8,R9,[%OrderLO],[%OrderHI]
    MOV [%FactLO],R8
    MOV [%FactHI],R9  ; Fact = Order!
    JMP .30:
.80:CLC
.90:EndProcedure FnExp
FnPower BaseLO, BaseHI, ExponentLO, ExponentHI
Procedure FnPower computes Base ^ Exponent for positive Base.
BE = e E * ln B
Input
BaseLo, BaseHI is the base.
ExponentLO, ExponentHI is the exponent.
Output
R9:R8 is the Base^Exponent.
CF=0
Error
CF=1 if the base is negative.
Clobbers
RAX,RBX,RCX,RDX,RSI,RDI,R10,R11,R12,R13,R14
FnPower:: Procedure BaseLO, BaseHI, ExponentLO, ExponentHI
      Invoke FnLn,[%BaseLO],[%BaseHI]
      JC .90:
      PUSH R8,R9                 ; Temporarily save ln Base.
      MOV R10,[%ExponentLO]
      MOV R11,[%ExponentHI]
      BT R11,31
      JC .50:                    ; Jump if exponent was negative.
      POP R9,R8
      Invoke FnMultiply,R8,R9,R10,R11 ; ln Base * Exponent
      Invoke FnExp,R8,R9         ; eul ^ (ln Base * Exponent)
      JMP .90:
.50:  Invoke Absolute,R10,R11    ; Exponent was negative. Put its absolute value to R9:R8.
      POP R11,R10
      Invoke FnMultiply,R8,R9,R10,R11 ; -Exponent * ln Base
      Invoke FnExp,R8,R9         ; eul ^ (ln Base * -Exponent)
      Invoke FnDivide,[One+0],[One+8],R8,R9 ; 1 / (eul ^ (ln Base * -Exponent))
.90: EndProcedure FnPower
FnLn NumberLO, NumberHI
Procedure FnLn computes natural logarithm of a positive number.
ln 1 = 0
ln eul = 1
ln (1/eul) = -1
It uses this algorithm.
Input
NumberLO, NumberHI is the input number.
Output
CF=0, R9:R8 is the natural logarithm in format N.
Error
CF=1 if Number < 0
Clobbers
FnLn:: Procedure NumberLO, NumberHI
DeltaLO      LocalVar
DeltaHI      LocalVar
ResultHI     LocalVar
ResultLO     LocalVar
PrevResultLO LocalVar
PrevResultHI LocalVar
    ClearLocalVar
    MOV EAX,1
    MOV [%DeltaLO],RAX    ; Start with delta=1.
    MOV R8,[%NumberLO]
    MOV R9,[%NumberHI]
    BT  R9,31
    JC .90:
    TEST R8
    JNZ .20:
    TEST R9D
    JNZ .20:
    STC
    JMP .90:
.20 Invoke Compare,[%NumberLO],[%NumberHI],[One+0],[One+8]
    JNE .30:
    XOR R8,R8
    XOR R9,R9
    JMP .90:
.30:Invoke Compare,[%NumberLO],[%NumberHI],[Eul+0],[Eul+8]
    JB .40:
    Invoke FnAdd,[%ResultLO],[%ResultHI],[%DeltaLO],[%DeltaHI]
    MOV [%ResultLO],R8
    MOV [%ResultHI],R9
    Invoke FnMultiply,[%NumberLO],[%NumberHI],[OneEulth+0],[OneEulth+8]
    MOV [%NumberLO],R8
    MOV [%NumberHI],R9
    JMP .30:
.40:Invoke Compare,[%NumberLO],[%NumberHI],[%DeltaLO],[%DeltaHI]
    JA .50:
    Invoke FnSubtract,[%ResultLO],[%ResultHI],[%DeltaLO],[%DeltaHI]
    MOV [%ResultLO],R8
    MOV [%ResultHI],R9
    Invoke FnMultiply,[%NumberLO],[%NumberHI],[Eul+0],[Eul+8]
    MOV [%NumberLO],R8
    MOV [%NumberHI],R9
    JMP .40:
.50: ; 1 < %Number < Eul
    Invoke FnMultiply, [%DeltaLO],[%DeltaHI],[Half+0],[Half+8]
    MOV [%DeltaLO],R8
    MOV [%DeltaHI],R9
    MOV R8,[%NumberLO]
    MOV R9,[%NumberHI]
    Invoke FnMultiply,R8,R9,R8,R9
    MOV [%NumberLO],R8
    MOV [%NumberHI],R9
    Invoke Compare,R8,R9,[Eul+0],[Eul+8]
    JB .50:
    Invoke FnMultiply,[%NumberLO],[%NumberHI],[OneEulth+0],[OneEulth+8]
    MOV [%NumberLO],R8
    MOV [%NumberHI],R9
    Invoke FnAdd,[%ResultLO],[%ResultHI],[%DeltaLO],[%DeltaHI]
    MOV [%ResultLO],R8
    MOV [%ResultHI],R9
    PUSH R8,R9
      Invoke Compare,R8,R9,[%PrevResultLO],[%PrevResultHI]
    POP R9,R8
    MOV [%PrevResultLO],R8
    MOV [%PrevResultHI],R9
    JNE .50:
    CLC
.90:EndProcedure FnLn
FnLg NumberLO, NumberHI
Procedure FnLg computes decadic logarithm of a positive number.
lg 1 =0
lg 10 = 1
lg x = ln x / ln 10 = ln x * OneLn10th
Input
NumberLO, NumberHI is the input number.
Output
CF=0, R9:R8 is the decadic logarithm in format N.
Error
CF=1 if Number < 0
FnLg:: Procedure NumberLO, NumberHI
     MOV R8,[%NumberLO]
     MOV R9,[%NumberHI]
     BT R9,31
     JC .90:
     Invoke FnLn,R8,R9
     JC .90:
     Invoke FnMultiply,R8,R9,[OneLn10th+0],[OneLn10th+8]
.90:EndProcedure FnLg
Compare Number1LO, Number1HI, Number2LO, Number2HI
Compare Number1 wth Number2. Both numbers are in format N.
N.EXP of both numbers will be united before comparison of N.MAN.
Input
Number1, Number2 are the two numbers in formatN to compare.
Output
CF, OF, ZF, SF are set.
Clobbers
RAX,RBX,RCX,RDX,R8,R9,R10,R11
Example
Invoke Compare, R8,R9, RSI,RDI JE Equal JG Nr1Greater ; Number1 in R9:R8 is greater than Number2 in RDI:RSI.
   %DROPMACRO Compare
Compare Procedure Number1LO, Number1HI, Number2LO, Number2HI
     MOV R8,[%Number1LO]
     MOV R9,[%Number1HI]
     MOV R10,[%Number2LO]
     MOV R11,[%Number2HI]
     CALL UniteExponent
     MOV EAX,R9D
     MOV EDX,R11D
     CMP EAX,EDX
     JNE .90:
     CMP R8,R10
.90:EndProcedure Compare
DisplayDecimal dNumberLO, dNumberHI, OutBuffer
Procedure DisplayDecimal prepares string with the representation of the Number. Significant digits are written to a Temporary array.
Input
dNumberLO, dNumberHI is the input number in format N.
OutBuffer is pointer to the output buffer for the result formated as decimal number, such as -123_456.789_012_345_678_901_234_567_E+2147483647. It should be at least 50 bytes long.
Output
RDI points behind the terminating 0 in the output string.
Clobbers
Temporary,RAX,RBX,RCX,RDX,RSI,R12,R13,R14,R8,R9,R10,R11
DisplayDecimalProxy:: PROC
  LEA RDI,[OutBuffer]
  Invoke DisplayDecimal,R8,R9,RDI
  RET
 ENDP DisplayDecimalProxy::

DisplayDecimal:: Procedure dNumberLO, dNumberHI, OutBuffer
Temporary   LocalVar Size=32
FirstSdigit LocalVar ; Pointer to the 1st significant (nonzero) digit  within Temporary.
LastSdigit  LocalVar ; Pointer to the last significant (nonzero) digit within Temporary.
PowerOf10   LocalVar ; Decadic exponent of the input number. May be displayed with E modifier.
DecPoint    LocalVar ; (Virtual) pointer to the decimal point within Temporary. May be outside the array.
    ClearLocalVar
    Invoke Absolute, [%dNumberLO], [%dNumberHI]
    MOV [%dNumberHI],R9
    MOV [%dNumberLO],R8
    MOV RDI,[%OutBuffer]
    MOV AL,'+'
    JNB .13:                 ; Absolute will set CF=1 on negative number.
    MOV AL,'-'
    STOSB
.13:MOV [%OutBuffer],RDI
    Invoke ZeroExponent, [%dNumberLO], [%dNumberHI]
    MOV [%PowerOf10],RDI     ; Decimal exponent of the number.
    LEA RDI,[%Temporary]
    CALL ConvertToDecimal    ; Fill the Temporary array with max. 29 digits. RDI is left behind the last digit.
    ADD RDI,[%PowerOf10]
    MOV [%DecPoint],RDI      ; Virtual pointer to the decimal point. It may be outside the Temporary array.
    XOR RAX,RAX
    MOV [%PowerOf10],RAX
    ; Find the first significant digit - the first nonzero digit from the left in Temporary.
    MOV AL,'0'
    LEA RDI,[%Temporary]
    MOV RCX,29
    REPE SCASB
    JZ .17:
    DEC RDI
.17:MOV [%FirstSdigit],RDI
    LEA RAX,[%Temporary+29]
    CMP RDI,RAX
    JNE .18:
    MOV AL,'0'
    MOV RDI,[%OutBuffer]
    STOSB
    JMP .85:
.18:; Find the last significant digit - the first nonzero digit from the right.
    LEA RCX,[%Temporary+28]
    MOV RDI,RCX
    SUB RCX,[%FirstSdigit]
    JNA .20:
    STD
    REPE SCASB
    CLD
    JZ .20:
    INC RDI
.20:MOV [%LastSdigit],RDI
    ; When there are more than 25 significant digits, round the unprecise three last digits.
    SUB RDI,[%FirstSdigit]
    CMP EDI,25
    JB .33:                   ; No rounding.
    LEA RDX,[%Temporary+26]
    MOV EAX,'0000'
    CMPB [RDX],'5'
    MOV [RDX],EAX
    JB .27:
.23:DEC RDX
    INCB [RDX]
    CMPB [RDX],'9'
    JBE .27:
    MOVB [RDX],'0'
    JMP .23:
.27:; The rounding is done. Find the FirstSdigit and LastSdigit again.
    MOV AL,'0'
    LEA RDI,[%Temporary]
    MOV RCX,29
    REPE SCASB
    JZ .28:
    DEC RDI
.28:MOV [%FirstSdigit],RDI
    LEA RCX,[%Temporary+28]
    MOV RDI,RCX
    SUB RCX,[%FirstSdigit]
    JNA .30:
    STD
    REPE SCASB
    CLD
    JZ .30:
    INC RDI
.30:MOV [%LastSdigit],RDI
.33:; Find the appropriate format of the result.
    MOV RDI,[%OutBuffer]
    ; Natural format has no decimal point and no exponent, e.g. 12_345_678,
    ;  it is used when DecPoint is above LastSdigit and below Temporary+30
    MOV RDX,[%DecPoint]
    CMP RDX,[%LastSdigit]
    JNA .47:
    LEA RAX,[%Temporary+30]
    CMP RDX,RAX
    JNB  .47:
    MOV RAX,RDX             ; Digits between FirstSdigit and DecPoint.
    MOV RSI,[%FirstSdigit]
    SUB RAX,RSI
    XOR EDX,EDX
    MOV EBX,3
    DIV RBX
    MOV EBX,EAX
    MOV ECX,EDX             ; Remainder.
    JRCXZ .36:
    REP MOVSB
    TEST EBX
    JZ .43:
    MOV AL,'_'
    STOSB
.36:MOV ECX,EBX             ; Dividend.
.40:JRCXZ .43:
    MOVSB
    MOVSB
    MOVSB
    CMP ECX,1
    JE .43:
    MOV AL,'_'
    STOSB
    LOOP .40:
.43:JMP .85:
.47: ; Format with nonzero integer part, decimal point and decimal part, e.g. 1_234.56 is used
     ;  when DecPoint is above FirstSdigit and
     ;  when DecPoint is between Temporary and Temporary+25.
    MOV RDX,[%DecPoint]
    CMP RDX,[%FirstSdigit]
    JNA .63:
    LEA RAX,[%Temporary+0]
    CMP RDX,RAX
    JB .63:
    LEA RAX,[%Temporary+25]
    CMP RDX,RAX
    JA .63:
    ; Digits between FirstSdigit and DecPoint.
    MOV RAX,RDX            ; DecPoint.
    MOV RSI,[%FirstSdigit]
    SUB RAX,RSI
    XOR EDX,EDX
    MOV EBX,3
    DIV RBX
    MOV EBX,EAX
    MOV ECX,EDX             ; Remainder.
    JRCXZ .50:
    REP MOVSB
.50:MOV ECX,EBX             ; Dividend.
    JRCXZ .57:
    TEST EDX
    JZ .53:
    MOV AL,'_'
    STOSB
.53:JRCXZ .57:
    MOVSB
    MOVSB
    MOVSB
    CMP ECX,1
    JBE .57:
    MOV AL,'_'
    STOSB
    LOOP .53:
.57:MOV AL,'.'
    STOSB
    MOV RSI,[%DecPoint]
    MOV RDX,[%LastSdigit]
    MOV AL,'_'
.60:MOVSB
    CMP RSI,RDX
    JA .85:
    MOVSB
    CMP RSI,RDX
    JA .85:
    MOVSB
    CMP RSI,RDX
    JA .85:
    STOSB
    JMP .60:
.63: ; Format with zero integer part, decimal point and decimal part, e.g. 0.012_34 is used
     ;  when DecPoint is below or equal FirstSdigit and
     ;  when DecPoint is between Temporary and Temporary+25.
    MOV RDX,[%DecPoint]
    CMP RDX,[%FirstSdigit]
    JNBE .70:
    LEA RAX,[%Temporary+0]
    CMP RDX,RAX
    JB .70:
    LEA RAX,[%Temporary+25]
    CMP RDX,RAX
    JA .70:
    MOV AX,'0.'
    STOSW
    MOV RSI,[%DecPoint]
    MOV RDX,[%LastSdigit]
    MOV AL,'_'
.67:MOVSB
    CMP RSI,RDX
    JA .85:
    MOVSB
    CMP RSI,RDX
    JA .85:
    MOVSB
    CMP RSI,RDX
    JA .85:
    STOSB
    JMP .67:
.70:; Otherwise a scientific format is used, which has exponent and
    ;  decimal point right behind the first significant digit, e.g.  1.234_56_E+123
    MOV RDX,[%DecPoint]
    MOV RSI,[%FirstSdigit]
    LEA RAX,[RSI+1]
    SUB RDX,RAX
    SUB [%DecPoint],RDX
    ADD [%PowerOf10],RDX
    MOVSB
    MOV AL,'.'
    STOSB
    MOV RDX,[%LastSdigit]
    CMP RSI,RDX
    JNA .73:
    MOV AL,'0'
    STOSB
    JMP .77:
.73:CMP RSI,RDX
    JA .77:
    MOVSB
    CMP RSI,RDX
    JA .77:
    MOVSB
    CMP RSI,RDX
    JA .77:
    MOVSB
    CMP RSI,RDX
    JA .77:
    MOV AL,'_'
    STOSB
    JMP .73:
.77:MOV RDX,[%PowerOf10]
    TEST RDX
    JZ .85:
    MOV AX,'_E'
    STOSW
    JS .80:
    MOV AL,'+'
    STOSB
.80:MOV RAX,RDX
    StoD RDI
.85:XOR EAX,EAX
    STOSB
.90:EndProcedure DisplayDecimal
Absolute NumberLO, NumberHI
Procedure Absolute calculates absolute value from the number.
Input
Number is the input number in format N.
Output
CF=0, R9:R8 input number unchanged when it was not negative.
CF=1, R9:R8 input number was < 0 and it was converted to positive in format N.
Clobbers
RAX
Absolute Procedure aNumberLO, aNumberHI
     MOV R9,[%aNumberHI]
     MOV R8,[%aNumberLO]
     TEST R9D
     JNS .90:
     MOV RAX,R9
     NOT R8
     NOT R9D
     ADD R8,1
     ADC R9D,0
     SHR RAX,32
     SHL RAX,32
     ADD R9,RAX
     STC
.90:EndProcedure Absolute
ConvertToDecimal
Procedure ConvertToDecimal converts the number from format N to a string of decimal digits.
The number must be positive and have EXP=0 (use Absolute and ZeroExponent prior to calling ConvertToDecimal).
Input
R9:R8 is the input number in format N, positive and with zero exponent.
RDI is pointer to a buffer 29 bytes long for the decimal digits.
Output
RDI points behind the last digit. The string in the buffer is filled with decimal digits '0'..'9'.
Clobbers
RAX,R8,R9,R10,R11
ConvertToDecimal   PROC
   ;    1   5   10   15   20   25   30   35   40
M  %FOR 0x0000_0000_204F_CE5E__3E25_0261_1000_0000, \ 10^28
        0x0000_0000_033B_2E3C__9FD0_803C_E800_0000, \ 10^27
        0x0000_0000_0052_B7D2__DCC8_0CD2_E400_0000, \ 10^26
        0x0000_0000_0008_4595__1614_0148_4A00_0000, \ 10^25
        0x0000_0000_0000_D3C2__1BCE_CCED_A100_0000, \ 10^24
        0x0000_0000_0000_152D__02C7_E14A_F680_0000, \ 10^23
        0x0000_0000_0000_021E__19E0_C9BA_B240_0000, \ 10^22
        0x0000_0000_0000_0036__35C9_ADC5_DEA0_0000, \ 10^21
        0x0000_0000_0000_0005__6BC7_5E2D_6310_0000, \ 10^20
        0x0000_0000_0000_0000__8AC7_2304_89E8_0000, \ 10^19
        0x0000_0000_0000_0000__0DE0_B6B3_A764_0000, \ 10^18
        0x0000_0000_0000_0000__0163_4578_5D8A_0000, \ 10^17
        0x0000_0000_0000_0000__0023_86F2_6FC1_0000, \ 10^16
        0x0000_0000_0000_0000__0003_8D7E_A4C6_8000, \ 10^15
        0x0000_0000_0000_0000__0000_5AF3_107A_4000, \ 10^14
        0x0000_0000_0000_0000__0000_0918_4E72_A000, \ 10^13
        0x0000_0000_0000_0000__0000_00E8_D4A5_1000, \ 10^12
        0x0000_0000_0000_0000__0000_0017_4876_E800, \ 10^11
        0x0000_0000_0000_0000__0000_0002_540B_E400, \ 10^10
        0x0000_0000_0000_0000__0000_0000_3B9A_CA00, \ 10^09
        0x0000_0000_0000_0000__0000_0000_05F5_E100, \ 10^08
        0x0000_0000_0000_0000__0000_0000_0098_9680, \ 10^07
        0x0000_0000_0000_0000__0000_0000_000F_4240, \ 10^06
        0x0000_0000_0000_0000__0000_0000_0001_86A0, \ 10^05
        0x0000_0000_0000_0000__0000_0000_0000_2710, \ 10^04
        0x0000_0000_0000_0000__0000_0000_0000_03E8, \ 10^03
        0x0000_0000_0000_0000__0000_0000_0000_0064, \ 10^02
        0x0000_0000_0000_0000__0000_0000_0000_000A  ; 10^01
      MOV R11,%M[1..21]
      MOV R10,0x%M[24..42]
      CALL .OneDigit
     %ENDFOR M
     MOV EAX,R8D
     OR AL,'0'
     STOSB
     JMP .90:
.OneDigit:
     MOV AL,'0'
.30: INC AL
     SUB R8,R10
     SBB R9D,R11D
     JNB .30:
     DEC AL      ; Rollback.
     ADD R8,R10
     ADC R9D,R11D
     STOSB
.90: RET
   ENDP ConvertToDecimal
MaximizeMantissa
While not overflow, double mantissa and decrement exponent.
Numeric value of the number is unchanged.
Input
R9:R8 is the input number
Output
R9:R8 is the modified number.
Clobbers
RAX,RCX,RDX
MaximizeMantissa PROC
     MOV RDX,R9
     SAR RDX,32
     MOV EAX,R9D
     OR RAX,R8
     JZ .90:
     MOV R9D,R9D         ; Clear EXP.
.10: DEC RDX
     SAL R8,1
     RCL R9D,1
     JNO .10:
     INC RDX            ; Rollback the overflow.
     RCR R9D,1
     RCR R8,1
     SAL RDX,32
     ADD R9,RDX
.90: RET
    ENDP MaximizeMantissa
NormalizeMantissa
If the four most significance bits of mantissa are set either all to 0 or all to 1, do nothing. Otherwise shift mantissa right and increment exponent.
Value of the number is almost unchanged.
Input
R9:R8 is the input number
Output
R9:R8 is the modified number.
Clobbers
NormalizeMantissa PROC
.10: MOV EAX,R9D
     SAR EAX,28
     JZ .90:
     INC EAX
     JZ .90:
     MOV RAX,R9
     SAR RAX,32
     INC RAX
     SAL RAX,32
     SAR R9D,1
     RCR R8,1
     JNC .50:
.50: ADD R9,RAX
     JMP .10:
.90: RET
    ENDP NormalizeMantissa
MinimizeMantissa
Decrease MAN and increase EXP while precision is kept.
Value of the number is unchanged. The four most significant bits of mantissa will be united (all 1 or all 0) even if this would make precision lost.
Input
R9:R8 is the input number
Output
R9:R8 is the modified number.
Clobbers
RAX,RCX,RDX
MinimizeMantissa PROC
     MOV EAX,R9D
     OR RAX,R8           ; Test if mantissa is 0.
     JNZ .30:
     XOR R9,R9           ; Clear EXP if so.
     JMP .90:
.30: TEST R8,1           ; Test LSb.
     JNZ .50:
     MOV RAX,R9
     SAR RAX,32
     INC RAX
     SAL RAX,32
     SAR R9D,1
     RCR R8,1
     ADD R9,RAX
     JMP .30:
.50: MOV EAX,R9D          ; Mantissa will further decrease only when its 4 MS bits are unequal to one another.
     SAR EAX,28
     JZ .90:              ; End when EAX=0.
     INC EAX
     JZ .90:              ; End when EAX=-1.
     MOV RAX,R9
     SAR RAX,32
     INC RAX              ; Increment exponent.
     SAL RAX,32
     SAR R9D,1            ; Decrease mantissa.
     RCR R8,1
     JNC .60:
.60: ADD R9,RAX
     JMP .50:
.90: RET
    ENDP MinimizeMantissa
UniteExponent
Modify exponent and mantissa of both numbers until both exponents are the same, which is neccessary for addition and subtraction.
It does not significantly change the values of both numbers.
Input
R9:R8 first input number,
R11:R10 second input number.
Output
Both input numbers are modified.
Clobbers
RAX,RCX,RDX
UniteExponent PROC
     MOV RCX,R9
     SAR RCX,32         ; EXP of R9:R8.
     MOV RDX,R11
     SAR RDX,32         ; EXP of R11:R10.
     MOV RAX,RCX
     SUB RAX,RDX
     JZ .80:            ; Both EXP are identical.
     JL .40:
.10: TEST RAX
     JZ .80:
     DEC RAX            ; EXP of R9:R8 is greater. Decrease it by at most RAX, but not to overflow it.
     DEC RCX            ; Decrease EXP of R9:R8.
     SAL R8,1           ; Increase MAN of R9:R8, so we could decrease EXP.
     RCL R9D,1
     JNO .10:
     INC RAX            ; Rollback, since overflow occured.
     INC RCX
     RCR R9D,1
     RCR R8,1
.20: TEST RAX           ; Cannot further increase MAN of R9:R8, thus we need to decrease MAN of R11:R10 by RAX.
     JZ .80:
     CMP R10,0
     JNE .30:
     CMP R11D,0
     JNE .30:
     ADD RDX,RAX        ; MAN of R11:R10 is 0, so there's no need to increase EXP=RDX one by one.
     JMP .80:
.30: DEC RAX
     INC RDX            ; Increase EXP of R11:R10.
     SAR R11D,1         ; Decrease MAN of R11:R10, so we could increase EXP.
     RCR R10,1
     JNC .20:
     JMP .20:
.40: NEG RAX
.50: TEST RAX
     JZ .80:
     DEC RAX            ; EXP of R11:R10 is greater. Decrease it by at most RAX, but not to overflow it.
     DEC RDX            ; Decrease EXP of R11:R10.
     SAL R10,1          ; Increase MAN of R11:R10, so we could decrease EXP.
     RCL R11D,1
     JNO .50:
     INC RAX            ; Rollback, since overflow occured.
     RCR R11D,1
     RCR R10,1
.60: TEST RAX           ; Cannot further increase MAN of R11:R10, thus decrease MAN of R9:R8 by RAX.
     JZ .80:
     CMP R8,0
     JNE .70:
     CMP R9D,0
     JNE .70:
     ADD RCX,RAX        ; MAN of R8:R9 is 0, so there's no need to increase EXP=RCX one by one.
     JMP .80:
.70: DEC RAX
     INC RCX            ; Increase EXP of R8:R9.
     SAR R9D,1          ; Decrease MAN of R8:R9, so we could increase EXP.
     RCR R8,1
     JMP .60:
.80: MOV R9D,R9D        ; Clear old EXP in R9.
     SAL RCX,32
     ADD R9,RCX
     MOV R11D,R11D      ; Clear old EXP in R11.
     SAL RDX,32
     ADD R11,RDX
     RET
   ENDP UniteExponent
ZeroExponent NumberLO, NumberHI
Procedure ZeroExponent repeatedly multiplies or divides the input number by 10 until the binary exponent N.EXP is zero.
Input
R9:R8 is the input number in format N.
Output
RDI is signed integer saying how many times was the input divided by 10.
R9:R8 is RDI times divided by 10, or multiplied by 10 when RDI < 0. Binary exponent (bits 32..63 of R9) is 0.
Clobbers
RAX,RBX,RCX,RDX,R12,R13,R14
ZeroExponent:: Procedure zeNumberLO, zeNumberHI
    SUB EDI,EDI         ; This will be power of 10 to multiply the output number.
    MOV R8,[%zeNumberLO]
    MOV R9,[%zeNumberHI]
    TEST R8
    JNZ .20:
    TEST R9D
    JNZ .20:
    XOR R9,R9
    JMP .90:
.20:CALL NormalizeMantissa
    MOV RCX,R9
    SAR RCX,32
    JZ .90:             ; Done, EXP=0.
    JS .50:             ; EXP is negative; multiply N by 10 and decrement RDI.
    CMP ECX,4           ; EXP is positive;   divide N by 10 and increment RDI,
    JB .70:             ;  unless EXP is a small positive.
    INC RDI
    Invoke FnMultiply, [%zeNumberLO],[%zeNumberHI],[OneTenth+0],[OneTenth+8]
.40:CALL NormalizeMantissa
    MOV [%zeNumberLO],R8
    MOV [%zeNumberHI],R9
    JMP .20:
.50:DEC RDI             ; N.EXP<0, multiply by 10.
    Invoke FnMultiply, [%zeNumberLO],[%zeNumberHI],[Ten+0],[Ten+8]
    JMP .40:
.70:JRCXZ .90:          ; RCX=0..3.
    SAL R8,1            ; RCX=1..3. Right-shift mantissa RCX times.
    RCL R9D,1
    LOOP .70:
.90:EndProcedure ZeroExponent     ; EDI is power of 10 to multiply the output number R9:R8.
Negate
Proc Negate calculates negated value of the number, as if it was multiplied by -1.
Input
R9:R8 are GPR with the input number in format N.
Output
R9:R8 is negated value of its previous value.
Clobbers
RAX
Negate PROC
     MOV RAX,R9
     SHR RAX,32
     SHL RAX,32
     NOT R8
     NOT R9D
     INC R8
     JNZ .90:
     INC R9D
.90: ADD R9,RAX
     RET
 ENDP Negate
    ENDPROGRAM calcmain

▲Back to the top▲