| Index | Manual | Download | Source | Macros | Embedded word Case ins.
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
  Value | Operation | Operator | Arity | Priority | Example
  --- | --- | --- | --- | --- | ---
  1 | FnEul | EUL | Function Euler's number with 0 operand | 15 | eul = 2.718_281_828_459_045_235_360_288
  2 | FnPi | PI | Function Ludolf's number with 0 operand | 15 | pi = 3.141_592_653_589_793_238_462_644
  3 | FnPlus | + | Unary operation | 12 | +2 = 2
  4 | FnMinus | - | Unary operation | 12 | -2 = -2
  5 | FnFactorial | ! | Reversed operation | 14 | 3 ! = 6
  6 | FnAdd | + | Binary operation | 2 | 2 + 3 = 5
  7 | FnSubtract | - | Binary operation | 2 | 2 - 3 = -1
  8 | FnMultiply | * | Binary operation | 4 | 2 * 3 = 6
  9 | FnDivide | / | Binary operation | 4 | 3 / 2 = 1.5
  10 | FnPower | ^ | Binary operation | 6 | 2 ^ 3 = 8
  11 | FnSin | SIN | Function sine with 1 operand | 10 | sin (pi / 6) = 0.5
  12 | FnCos | COS | Function cosine with 1 operand | 10 | cos (pi / 6) = 0.5
  13 | FnTan | TAN | Function tangent with 1 operand | 10 | tan (pi / 4) = 1
  14 | FnCot | COT | Function cotangent with 1 operand | 10 | cot (pi / 4) = 1
  15 | FnSec | SEC | Function secant with 1 operand | 10 | sec pi = -1
  16 | FnCsc | CSC | Function cosecant with 1 operand | 10 | csc (pi/2) = 1
  17 | FnExp | EXP | Function exponent with 1 operand | 10 | exp 1 = 2.718_281_828_459_045_235_360_288
  18 | FnLn | LN | Function natural logarithm with 1 operand | 10 | ln eul = 1
  19 | FnLg | LG | Function decimal logarithm with 1 operand | 10 | lg 100 = 2

  Examples
  Number | Alias | Mantissa | Exponent | N
  --- | --- | --- | --- | ---
  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_FFFF | 0x7FFF_FFFF | 0x7FFF_FFFF_7FFF_FFFF_FFFF_FFFF_FFFF_FFFF
  -∞ | 0x8000_0000_0000_0000_0000_0000 * 2 ^ 0x7FFF_FFFF | 0x8000_0000_0000_0000_0000_0000 | 0x7FFF_FFFF | 0x7FFF_FFFF_8000_0000_0000_0000_0000_0000
  +1/∞ | 0x0000_0000_0000_0000_0000_0001 * 2 ^ 0x8000_0001 | 0x0000_0000_0000_0000_0000_0001 | 0x8000_0001 | 0x8000_0001_0000_0000_0000_0000_0000_0001
  -1/∞ | 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF * 2 ^ 0x8000_0001 | 0x0000_0000_0000_0000_0000_0001 | 0x8000_0001 | 0x8000_0001_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF
  Fn #12h | 0x0000_0000_0000_0000_0000_0012 * 2 ^ 0x8000_0000 | 0x0000_0000_0000_0000_0000_0012 | 0x8000_0000 | 0x8000_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▲