老刘 发表于 2019-2-19 20:44

[算法实战002]高精度正负浮点数四则运算

本帖最后由 老刘 于 2019-2-19 20:47 编辑



高精度正负浮点数四则运算.ASM
;高精度正负浮点数四则运算 Algo
;Code By 老刘
;编译环境:MASM32 SDK
;编译指令:ml /coff 高精度正负浮点数四则运算.ASM /link /subsystem:console
;调用方法:
;      传参,参数1为数1对数2进行的运算(+、-、*、/),
;      参数2、3为分别为数1,数2参数。
;合规数字:1 01 1.0 00.100 -01.1234      (不和规数字:.1 3.)
;其他:
;      两个数字的最大长度为124位(包含负号、小数点、0)。
;      受MASM32 SDK中老旧的ArgClC函数限制,两个数字的总长度和应不超过188。
;      应尽量避免多余0的出现(如0100中开头的0、0.0010中最后的0),会削减除法运算的精度。
;参考:MHL批处理标准教程之高精度系列代码。


Include masm32rt.inc
Main Proto      ;主函数
_Addition Proto      ;加(减)法函数
_ArraySubtraction Proto      lpMinuend:dword,lpSubtrahend:dword,bArrayLength:byte      ;数组减法函数
_ArrayCompare Proto lpArray1:dword,lpArray2:dword,bArrayLength:byte      ;数组(表示的数字的)大小比较函数
_Multiplication Proto      ;乘法函数
_Division Proto      ;除法函数

.Data?
      szNum1 DB 128 Dup (?)
      szNum2 DB 128 Dup (?)
      bNum1Symbol DB ?
      bNum2Symbol DB ?
      bNum1Length DB ?
      bNum2Length DB ?
      bNum1IntegralPartLength DB ?
      bNum1DecimalPartLength DB ?
      bNum2IntegralPartLength DB ?
      bNum2DecimalPartLength DB ?
      bNum1LengthPlusNum2Length DB ?
      bNum1IntegralPartLengthPlusNum2IntegralPartLength DB ?
      bNum1DecimalPartLengthPlusNum2DecimalPartLength DB ?
      bNum1LengthPlusNum2DecimalPartLength DB ?
      bNum2LengthPlusNum1DecimalPartLength DB ?
      lpNum1IntegralPart DD ?
      lpNum1DecimalPart DD ?
      lpNum2IntegralPart DD ?
      lpNum2DecimalPart DD ?
;End Data?

.Code
      Main Proc
                Local @szOperation:word      ;运算符+null的长度
               
                ;获得参数并赋值变量
                Invoke ArgClC,1,Addr @szOperation
                Invoke ArgClC,2,Addr szNum1
                Invoke ArgClC,3,Addr szNum2
               
                Lea Eax,szNum2
                Mov lpNum2IntegralPart,Eax      ;初步确定指针
                Lea Esi,szNum1
                Mov lpNum1IntegralPart,Esi
               
                ;正负号判断(0正1负)
                LodSB      ;Esi=lpNum1IntegralPart
                .If Al == '-'
                        Mov bNum1Symbol,1
                        Inc lpNum1IntegralPart      ;指针修正,使其指向数字
                .Else
                        Mov bNum1Symbol,0
                .EndIf
                Mov Ax,@szOperation
                Mov Ah,Al
                Mov Esi,lpNum2IntegralPart
                LodSB
                .If Ah == '-'      ;负负得正的处理
                        .If Al == '-'
                              Mov bNum2Symbol,0
                              Inc lpNum2IntegralPart
                        .Else
                              Mov bNum2Symbol,1
                        .EndIf
                .Else
                        .If Al == '-'
                              Mov bNum2Symbol,1
                              Inc lpNum2IntegralPart
                        .Else
                              Mov bNum2Symbol,0
                        .EndIf
                .EndIf
               
                ;获得两数的小数、整数部分长度;
                ;获得两数的小数部分的内存地址;
                ;去掉小数点;将数字从Ascii转为Byte。
                Mov bNum1IntegralPartLength,0
                Mov bNum1DecimalPartLength,0
                Mov bNum2IntegralPartLength,0
                Mov bNum2DecimalPartLength,0
                Mov Esi,lpNum1IntegralPart
                Mov Edi,Esi      ;同时操作一个字符串
                Lea Ebx,bNum1IntegralPartLength
                Lea Ecx,bNum1DecimalPartLength
                Xor Edx,Edx      ;作为循环flag
                @@:
                LodSB
                .While Al != '.' && Al != NULL
                        Inc Byte Ptr
                        Sub Al,30H      ;将数字从Ascii转为Byte
                        StoSB      ;重新写回去
                        LodSB
                .EndW
                Push Esi
                .If Al != NULL
                        LodSB
                        .While Al != NULL
                              Inc Byte Ptr
                              Sub Al,30H
                              StoSB
                              LodSB
                        .EndW
                .EndIf
                .If Edx == 0
                        Pop lpNum1DecimalPart
                        Mov Esi,lpNum2IntegralPart
                        Mov Edi,Esi
                        Lea Ebx,bNum2IntegralPartLength
                        Lea Ecx,bNum2DecimalPartLength
                        Inc Edx
                        Jmp @B
                .EndIf
                Pop lpNum2DecimalPart
                Dec lpNum1DecimalPart      ;去掉了小数点后的指针修正
                Dec lpNum2DecimalPart
               
                ;计算各种长度。
                Mov Al,bNum1IntegralPartLength
                Add Al,bNum1DecimalPartLength
                Mov bNum1Length,Al
                Add Al,bNum2DecimalPartLength
                Mov bNum1LengthPlusNum2DecimalPartLength,Al
                Add Al,bNum2IntegralPartLength
                Mov bNum1LengthPlusNum2Length,Al
                Sub Al,bNum1IntegralPartLength
                Mov bNum2LengthPlusNum1DecimalPartLength,Al
                Sub Al,bNum1DecimalPartLength
                Mov bNum2Length,Al
                Sub Al,bNum2DecimalPartLength
                Add Al,bNum1IntegralPartLength
                Mov bNum1IntegralPartLengthPlusNum2IntegralPartLength,Al
                Sub Al,bNum1LengthPlusNum2Length
                Mov Al,bNum1LengthPlusNum2Length
                Sub Al,bNum1IntegralPartLengthPlusNum2IntegralPartLength
                Mov bNum1DecimalPartLengthPlusNum2DecimalPartLength,Al
               
                ;调用相应的计算函数。
                Mov Ax,@szOperation
                .If Al == '+' || Al == '-'
                        Call _Addition
                .ElseIf Al == '*'
                        Call _Multiplication
                .ElseIf Al == '/'
                        Call _Division
                .EndIf
               
                Ret
      Main EndP
      
      _Addition Proc
                Local @bNum1Array:byte,@bNum2Array:byte      ;其中之一同时作为结果数组
                Local @bDestSymbol:byte,@lpDestArray
                Local @bDestEqualZeroSign:byte,@bDestDecimalPartEqualZeroSign:byte
                Local @bDestDecimalPartLength:byte,@szDest:byte
                Mov Al,bNum1DecimalPartLengthPlusNum2DecimalPartLength      ;初步确定结果小数部分长度
                Mov @bDestDecimalPartLength,Al
               
                ;数组清0。
                Xor Eax,Eax
                Mov Ecx,SizeOf @bNum1Array
                Lea Edi,@bNum1Array
                Rep StoSB
                Mov Ecx,SizeOf @bNum2Array
                Lea Edi,@bNum2Array
                Rep StoSB
               
                ;数1存入数组。
                Mov Esi,lpNum1IntegralPart
                Lea Edi,@bNum1Array
                Movzx Eax,bNum1LengthPlusNum2DecimalPartLength
                Add Edi,Eax
                Dec Edi ;数组从0开始
                Movzx Ecx,bNum1Length
                .Repeat
                        MovSB
                        Dec Edi      ;倒序装入数组
                        Dec Edi
                .UntilCxZ
               
                ;数2存入数组。
                Mov Esi,lpNum2IntegralPart
                Lea Edi,@bNum2Array
                Movzx Eax,bNum2LengthPlusNum1DecimalPartLength
                Add Edi,Eax
                Dec Edi
                Movzx Ecx,bNum2Length
                .Repeat
                        MovSB
                        Dec Edi
                        Dec Edi
                .UntilCxZ
               
                ;判断同异号并计算结果。
                Mov @bDestEqualZeroSign,0FFH
                Mov Al,bNum1Symbol
                Xor Al,bNum2Symbol
                .If Al == 0      ;同号
                        ;获取结果符号。
                        Mov Al,bNum1Symbol
                        Mov @bDestSymbol,Al
                        
                        ;计算结果。
                        Xor Eax,Eax      ;Ah进位清0
                        Lea Esi,@bNum2Array
                        Lea Edi,@bNum1Array      ;作为结果数组
                        Mov @lpDestArray,Edi
                        Movzx Ecx,bNum1LengthPlusNum2Length      ;计数器
                        Mov Bl,10      ;十进制
                        .Repeat
                              LodSB
                              Add Al,
                              Add Al,Ah
                              Cbw
                              Div Bl
                              Xchg Al,Ah
                              StoSB
                        .UntilCxZ
                .Else      ;异号
                        ;比较两数大小并获取结果符号。
                        Invoke _ArrayCompare,Addr @bNum1Array,Addr @bNum2Array,bNum1LengthPlusNum2Length
                        .If Eax == 1      ;(绝对值)数1>数2
                              Mov Al,bNum1Symbol
                              Mov @bDestSymbol,Al
                              Lea Edi,@bNum1Array      ;作为结果数组
                              Mov @lpDestArray,Edi
                              Invoke _ArraySubtraction,Edi,Addr @bNum2Array,bNum1LengthPlusNum2Length
                        .ElseIf Eax == 2
                              Mov Al,bNum2Symbol
                              Mov @bDestSymbol,Al
                              Lea Edi,@bNum2Array
                              Mov @lpDestArray,Edi
                              Invoke _ArraySubtraction,Edi,Addr @bNum1Array,bNum1LengthPlusNum2Length
                        .Else      ;两数相等
                              Inc @bDestEqualZeroSign      ;=0
                        .EndIf
                .EndIf
               
                ;验证加法结果是否为0。
                ;(其实就是应对0+0或-0-0这样的情况)
                Mov Al,@bDestEqualZeroSign
                .If Al == 0FFH
                        Mov Esi,@lpDestArray
                        Movzx Ecx,bNum1LengthPlusNum2Length
                        .Repeat
                              LodSB
                        .UntilCxZ Al != 0
                        .If Al == 0      ;全部跑完,且值为0
                              Inc @bDestEqualZeroSign
                        .EndIf
                .EndIf
               
                ;结果转为字符串。
                Mov Al,@bDestEqualZeroSign
                .If Al == 0FFH      ;值为FF在此表示值不为0
                        Mov Al,@bDestDecimalPartLength
                        .If Al != 0      ;两整数相加时小数部分肯定为0
                              ;修正结果小数部分长度。
                              Mov Esi,@lpDestArray
                              Movzx Ecx,@bDestDecimalPartLength
                              .Repeat
                                        LodSB
                              .UntilCxZ Al != 0
                              .If Al != 0      ;小数部分不为0
                                        Inc Cl      ;长度从1开始
                                        Mov @bDestDecimalPartLength,Cl
                              .Else
                                        Mov @bDestDecimalPartLength,Al      ;=0
                              .EndIf
                        .EndIf
                        
                        ;结果字符串写入。
                        Lea Edi,@szDest
                        ;结果符号判断&写入。
                        Mov Al,@bDestSymbol
                        .If Al == 1      ;结果为负
                              Mov Al,'-'
                              StoSB
                        .EndIf
                        ;结果的整数部分转为字符串。
                        Movzx Esi,bNum1LengthPlusNum2Length
                        Add Esi,@lpDestArray
                        Dec Esi
                        Movzx Ecx,bNum1IntegralPartLengthPlusNum2IntegralPartLength
                        .Repeat      ;去除先导0
                              LodSB
                              Dec Esi
                              Dec Esi
                        .UntilCxZ Al !=0
                        Add Al,30H      ;Byte转Ascii
                        StoSB      ;整数部分的最高位或0写入
                        .While Ecx != 0      ;剩余整数部分写入
                              LodSB
                              Dec Esi
                              Dec Esi
                              Add Al,30H
                              StoSB
                              Dec Ecx
                        .EndW
                        ;结果小数点及小数部分转为字符串。
                        Movzx Ecx,@bDestDecimalPartLength      ;计数器
                        .If Cl != 0
                              Mov Al,'.'
                              StoSB      ;小数点写入
                              .Repeat
                                        LodSB
                                        Dec Esi
                                        Dec Esi
                                        Add Al,30H
                                        StoSB
                              .UntilCxZ
                        .EndIf
                        Mov DWord Ptr ,000A0DH      ;字符串结尾
                .Else
                        ;结果字符串写入
                        Lea Edi,@szDest
                        Mov DWord Ptr ,000A0D30H      ;"0\r\n"+null
                .EndIf
               
                ;输出结果。
                Invoke StdOut,Addr @szDest
               
                Xor Eax,Eax
                Ret
      _Addition EndP
      
      _ArraySubtraction Proc Uses Eax Ebx Ecx Esi Edi lpMinuend:dword,lpSubtrahend:dword,bArrayLength:byte
                ;参数:被减数数组指针、减数数组指针、两个数组的共同长度。
                ;要求:被减数大于减数。
               
                Mov Edi,lpMinuend
                Mov Esi,lpSubtrahend
                Movzx Ecx,bArrayLength
                Xor Ebx,Ebx      ;Bl借位清0
                .Repeat
                        Mov Al,
                        Sub Al,Bl
                        Sub Al,
                        .If Sign?      ;结果为负
                              Add Al,10
                              Mov Bl,1
                        .Else
                              Xor Ebx,Ebx
                        .EndIf
                        StoSB
                        Inc Esi
                .UntilCxZ
               
                Ret
      _ArraySubtraction EndP
      
      _ArrayCompare Proc Uses Edi Esi Ecx lpArray1:dword,lpArray2:dword,bArrayLength:byte
                ;参数:数组1、数组2、两个数组的共同长度。
                ;返回值(存于Eax中):0-两数(组)相等;1-数1大于数2;2-数2大于数1。
               
                Mov Edi,lpArray1
                Mov Esi,lpArray2
                Movzx Ecx,bArrayLength      ;计数器
                Add Esi,Ecx
                Dec Esi      ;指向数组最后一个元素
                Add Edi,Ecx
                Dec Edi
               
                .Repeat
                        Xchg Esi,Edi
                        LodSB      ;数1
                        Dec Esi
                        Dec Esi
                        Mov Ah,Al
                        Xchg Esi,Edi
                        LodSB      ;数2
                        Dec Esi
                        Dec Esi
                        .If Ah > Al      ;(绝对值)数1>数2
                              Mov Eax,1
                              Ret
                        .ElseIf Ah < Al
                              Mov Eax,2
                              Ret
                        .EndIf
                .UntilCxZ
                Xor Eax,Eax      ;能运行到这里,说明两数相等。
               
                Ret
      _ArrayCompare EndP
      
      _Multiplication Proc
                Local @bDestArray:byte,@bDestDecimalPartLength:byte,@szDest:byte
                Local @bDestEqualZeroSign:byte,@bDestSymbol:byte
               
                ;结果数组清0。
                Xor Eax,Eax
                Mov Ecx,SizeOf @bDestArray
                Lea Edi,@bDestArray
                Rep StoSB
               
                ;数1、数2从低到高按位相乘并放入结果数组。
                Lea Edi,@bDestArray
                Mov Ebx,lpNum1IntegralPart
                Movzx Edx,bNum1Length
                Add Ebx,Edx
                Dec Ebx      ;指针修正
                Xchg Dh,Dl      ;Dh做计数器
                ;使用数1的每一位乘数2的全部位。
                .While Dh != 0
                        Mov Dl,      ;Dl做因数
                        Push Edi
                        
                        ;数2初始化。
                        Mov Esi,lpNum2IntegralPart
                        Movzx Ecx,bNum2Length      ;Ecx做计数器
                        Add Esi,Ecx
                        Dec Esi
                        .Repeat
                              LodSB
                              Dec Esi      ;逆读取指针修正;数2换高一位
                              Dec Esi
                              Mul Dl
                              Add ,Al
                              Inc Edi
                        .UntilCxZ
                        
                        ;进位处理,避免溢出。
                        Movzx Ecx,bNum2Length      ;要处理进位的长度=数2的长度
                        Mov Edi,      ;使Edi指向需进位处理的首个数字
                        Mov Dl,10
                        .Repeat
                              Movzx Ax,Byte Ptr
                              Div Dl
                              Mov ,Ah
                              Add ,Al
                              Inc Edi
                        .UntilCxZ
                        
                        ;根据乘法法则,数1换高一位,结果也换高一位。
                        Pop Edi
                        Dec Ebx
                        Inc Edi
                        
                        Dec Dh
                .EndW
               
                ;判断结果是否为0;
                ;获得结果符号。
                Movzx Ecx,bNum1DecimalPartLength
                Add Cl,bNum2DecimalPartLength
                Mov @bDestEqualZeroSign,0
                Lea Esi,@bDestArray
                .If Cl > 0
                        .Repeat
                              LodSB
                        .UntilCxZ Al != 0
                        .If Al != 0      ;小数部分非0
                              ;小数部分非0说明乘积不为0,获得结果符号。
                              Mov Al,bNum1Symbol
                              Xor Al,bNum2Symbol
                              Mov @bDestSymbol,Al
                              
                              Inc Ecx
                              Mov @bDestDecimalPartLength,Cl
                        .Else
                              Mov @bDestDecimalPartLength,0
                              ;判断整数部分是否为0。
                              Movzx Ecx,bNum1IntegralPartLength
                              Add Cl,bNum2IntegralPartLength
                              .Repeat
                                        LodSB
                              .UntilCxZ Al != 0
                              .If Al == 0      ;乘积为0,不管正负,使结果为正(避免输出-0)
                                        Mov @bDestSymbol,0
                                        Inc @bDestEqualZeroSign      ;=1
                              .EndIf
                        .EndIf
                .Else      ;结果不存在小数部分
                        Mov @bDestDecimalPartLength,0
                .EndIf
               
                ;生成结果字符串。
                Lea Esi,@bDestArray
                Movzx Ecx,bNum1Length
                Add Cl,bNum2Length
                Add Esi,Ecx      ;使得Esi指向数组末尾
                Lea Edi,@szDest
                .If @bDestEqualZeroSign == 1
                        Mov DWord Ptr ,000A0D30H      ;"0\r\n"+null
                .ElseIf
                        ;获得整数部分长度。
                        Movzx Ecx,bNum1IntegralPartLength
                        Add Cl,bNum2IntegralPartLength
                        
                        ;写入符号。
                        .If @bDestSymbol == 1
                              Mov Al,'-'
                              StoSB
                        .EndIf
                        
                        ;略过整数部分开头的0。
                        .Repeat
                              Dec Esi
                              LodSB
                              Dec Esi
                        .UntilCxZ Al != 0
                        Inc Ecx
                        
                        ;写入整数部分。
                        .Repeat
                              LodSB
                              Dec Esi
                              Dec Esi
                              Add Al,30H      ;Byte转Ascii
                              StoSB
                        .UntilCxZ
                        
                        ;写入小数部分(如果有)。
                        Movzx Ecx,@bDestDecimalPartLength
                        .If Cl > 0
                              ;写入小数点。
                              Mov Al,'.'
                              StoSB
                              ;写入小数部分。
                              .Repeat
                                        LodSB
                                        Dec Esi
                                        Dec Esi
                                        Add Al,30H
                                        StoSB
                              .UntilCxZ
                        .EndIf
                        
                        ;字符串结尾。
                        Mov DWord Ptr ,000A0DH
                .EndIf
               
                ;输出结果。
                Invoke StdOut,Addr @szDest
               
                Xor Eax,Eax
                Ret
      _Multiplication EndP
      
      _Division Proc
                Local @szDest:byte,@bDividendArray:byte,@bDivisorArray:byte,@lpDest
                Local @bDestDecimalPointPos:byte,@bDivisorArrayLength:byte
                Local @bDestEqualZeroSign:byte,@bDestIntegralPartEqualZeroSign:byte,@bDecimalPointWriteInSign:byte
               
                ;将除数的有效数字存入除数数组。
                Mov Esi,lpNum2IntegralPart
                Movzx Ecx,bNum2IntegralPartLength
                .Repeat      ;去除整数部分多余的0
                        LodSB
                .UntilCxZ Al != 0
                .If Al != 0
                        Inc Ecx
                        Mov bNum2IntegralPartLength,Cl
                        Dec Esi      ;指向有效数字
                        Add Cl,bNum2DecimalPartLength
                .Else      ;整数部分均为0,继续去0直到遇到有效数字
                        Mov bNum2IntegralPartLength,0
                        Movzx Ecx,bNum2DecimalPartLength
                        .If Ecx != 0      ;除数存在小数部分
                              .Repeat
                                        LodSB
                              .UntilCxZ Al != 0
                              .If Al != 0
                                        Inc Ecx
                                        Dec Esi      ;指向有效数字
                              .Else      ;除数为0
                                        Mov Eax,1
                                        Ret
                              .EndIf
                        .Else      ;不存在小数部分,除数为0
                              Mov Eax,1
                              Ret
                        .EndIf
                .EndIf
                ;按位(倒序)存入除数数组。
                Mov @bDivisorArrayLength,Cl      ;有效数字到除数末尾的长度
                Lea Edi,@bDivisorArray
                Add Edi,Ecx
                Dec Edi      ;指向数组最后一个元素
                .Repeat
                        LodSB
                        StoSB
                        Dec Edi
                        Dec Edi
                .UntilCxZ
                ;为配合运算,将除数数组增加一个元素;
                ;不影响除数数组代表的除数的大小。
                Movzx Ecx,@bDivisorArrayLength
                Inc @bDivisorArrayLength
                Lea Eax,@bDivisorArray      ;此时Eax+Ecx指向新增的元素
                Mov Byte Ptr ,0      ;清0
               
                ;计算结果小数点的位置。
                Mov Al,bNum1IntegralPartLength
                Add Al,bNum2DecimalPartLength
                Mov @bDestDecimalPointPos,Al
               
                ;判断被除数是否为0;
                ;判断结果符号并写入。
                Mov Esi,lpNum1IntegralPart
                Movzx Ecx,bNum1Length
                .Repeat
                        LodSB
                .UntilCxZ Al != 0
                .If Al == 0
                        Mov @bDestEqualZeroSign,1
                        Lea Eax,@szDest
                        Mov DWord Ptr ,000A0D30H      ;"0\r\n"+null
                .Else
                        Mov @bDestEqualZeroSign,0
                        Mov Al,bNum1Symbol
                        Xor Al,bNum2Symbol
                        .If Al == 0      ;结果为正
                              Lea Eax,@szDest
                              Mov @lpDest,Eax
                        .Else      ;结果为负
                              Lea Eax,@szDest
                              Mov Byte Ptr ,'-'
                              Inc Eax
                              Mov @lpDest,Eax
                        .EndIf
                .EndIf
               
                ;被除数数组清空。
                Xor Eax,Eax
                Mov Ecx,SizeOf @bDividendArray
                Lea Edi,@bDividendArray
                Rep StoSB
               
                ;进行除法运算并生成最终字符串。
                .If @bDestEqualZeroSign != 1
                        ;获得被除数数组起始元素地址;
                        Lea Esi,@bDividendArray
                        Mov Ebx,SizeOf @bDividendArray
                        Dec Ebx      ;此时Esi+Ebx指向被除数数组末尾
                        Sub Bl,@bDivisorArrayLength      ;作为计算终止的标识之一
                        Add Esi,Ebx      ;此时Esi指向(当前的)被除数数组起始元素地址
                        Mov Bh,bNum1Length
                        Mov Ecx,lpNum1IntegralPart      ;作为被除数的读取指针
                        Sub Bl,4      ;减小精度,为字符串中数字以外的其它字符保留空间
                        Mov Edi,@lpDest      ;Edi作为字符串指针
                        Mov Dh,@bDestDecimalPointPos      ;Dh作为小数点写入的标识
                        Mov @bDestIntegralPartEqualZeroSign,0
                        
                        ;开始除法(减法模拟)运算。
                        .While Bl > 0
                              Invoke _ArrayCompare,Esi,Addr @bDivisorArray,@bDivisorArrayLength
                              Dec Bl
                              .If Eax <= 1      ;被除数数组>=除数数组,做减法
                                        Xor Dl,Dl      ;Dl作为商
                                        .While Eax != 2
                                                Invoke _ArraySubtraction,Esi,Addr @bDivisorArray,@bDivisorArrayLength
                                                Invoke _ArrayCompare,Esi,Addr @bDivisorArray,@bDivisorArrayLength
                                                Inc Dl
                                        .EndW
                                        Mov Al,Dl
                                        Add Al,30H
                                        StoSB
                                        Mov @bDestIntegralPartEqualZeroSign,1
                              .Else      ;被除数数组已经(被减到)小于除数数组
                                        ;用被除数将被除数数组添加一位。
                                        Dec Esi
                                        .If Bh > 0      ;被除数未全部放入数组
                                                Mov Al,Byte Ptr
                                                Mov Byte Ptr ,Al
                                                Inc Ecx
                                                Dec Bh
                                        .EndIf
                                        ;若被除数全部放入数组,则只需添0,由于数组已经清空,无需处理。
                                       
                                        ;判断是否需要向字符串中写入小数点。
                                        .If Dh == 0 && @bDecimalPointWriteInSign == 0
                                                Mov @bDecimalPointWriteInSign,1
                                                .If @bDestIntegralPartEqualZeroSign == 0
                                                      Mov @bDestIntegralPartEqualZeroSign,1
                                                      Mov Al,'0'
                                                      StoSB
                                                .EndIf
                                                Mov Al,'.'
                                                StoSB
                                        .EndIf
                                        Dec Dh
                                       
                                        ;判断是否处理完成;
                                        ;写入0。
                                        Invoke _ArrayCompare,Esi,Addr @bDivisorArray,@bDivisorArrayLength
                                        .If Eax == 2
                                                .If Bh == 0 && @bDecimalPointWriteInSign == 1      ;被除数非零数全部放入数组且被除数整数部分除完
                                                      Movzx Ecx,@bDivisorArrayLength      ;判断被除数数组是否除完(全空)
                                                      .Repeat
                                                                Lea Eax,
                                                                Mov Al,Byte Ptr
                                                      .UntilCxZ Al != 0
                                                      .If Al == 0
                                                                .If Dh == 0FFH      ;小数点刚写入,已经计算完成
                                                                        Dec Edi      ;去掉小数点
                                                                .EndIf
                                                                .Break
                                                      .EndIf
                                                .EndIf
                                                .If @bDestIntegralPartEqualZeroSign == 1
                                                      Mov Al,'0'
                                                      StoSB
                                                .EndIf
                                        .EndIf
                              .EndIf
                        .EndW
                .EndIf
                Mov DWord Ptr ,00000A0DH      ;字符串结尾
               
                ;输出结果。
                Invoke StdOut,Addr @szDest
               
                Xor Eax,Eax
                Ret
      _Division EndP
      
      Start:
                Call Main
                Invoke ExitProcess,Eax
      End Start
End
测试-计算圆周率.BAT
@Rem 公式:pi=2*1+2*1!/3!!+2*2!/5!!+2*3!/7!!+...+2*k!/(2*k+1)!!+...

@echo off
Setlocal enabledelayedexpansion
::CODER BY 老刘 POWERD BY iBAT
Set Calc=高精度正负浮点数四则运算
Title 任意键提高精度
Set /a k=0,sss=1
:loop
      Set /a k+=1,n=2*k+1
      Call :! !k!
      Set aaa=!Re!
      Call :!! !n!
      Set bbb=!Re!
      For /f %%b in ('!calc! / %aaa:~,93% %bbb:~,93%') Do Set ccc=%%b
      For /f %%b in ('!calc! + %ccc:~,93% %sss:~,93%') Do Set sss=%%b
      For /f %%b in ('!calc! * %sss:~,93% 2') Do Echo %%b
      Pause>nul
Goto :loop

:! 阶乘
      Set Re=1
      For /l %%a in (1 1 %1) Do (
                For /f %%b in ('!calc! * !re! %%a') Do Set Re=%%b
      )
Goto :Eof

:!! 双阶乘
      Set Re=1
      For /l %%a in (1 2 %1) Do (
                For /f %%b in ('!calc! * !re! %%a') Do Set Re=%%b
      )
Goto :Eof

2.6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
2.9333333333333333333333333333333333333333333333333333333333333333333333333333333333333333332
3.0476190476190476190476190476190476190476190476190476190476190476190476190476190476190476188
3.0984126984126984126984126984126984126984126984126984126984126984126984126984126984126984124
3.1215007215007215007215007215007215007215007215007215007215007215007215007215007215007215004
3.1321567321567321567321567321567321567321567321567321567321567321567321567321567321567321564
3.1371295371295371295371295371295371295371295371295371295371295371295371295371295371295371292
3.1394696806461512343865285041755629990924108571167394696806461512343865285041755629990924104
3.140578169680336862999401699092101568881754640268572157117048757915630980646460522621513333
3.1411060216013776385293413157190246973528707274837305797058119039543188149999295510131423438
3.1413584725201362703045298280188574979260132039779367818134812346684738662124582167656605662
3.141479648961140413556620313922777242201121592695155758825162513411268290794471976326869313
3.141537993173475741789108325654294156111358965040483414423379425398539680408034156856340191
3.1415661593449479692116887451108885283438873516899519378156220725648086271180296922843606148
3.1415797881375958211903566900092406439402720549074367071989652889355839239131888223301769488
3.1415863960370614463921350875357143969567010019219747772030104847517174011472053702311788076
3.1415896055882304643472845949057159341361093476147504112049752941481250900894419792116654248
3.141591166991501878487627598491122087358524218492316935854579796016647749574854383580550806
3.1415919276751469264021536771609353414925212068685672940172076302602869939395424780166744532
3.1415922987403396327019224960242588800944709572960064931209285250132817472881708167660030616
3.1415924799582244427552979657016959570861208354117326136134433805903256965979660519691635446
3.1415925685536347943369481953217763058375941091571987169653395322057694051494215002907086696
3.1415926119088356046854153289656454126734214558837034058396716915069439859299209750012520286
(不求效率,仅做测试)

算个前7位真不容易……

wuyounanhai 发表于 2019-2-19 20:56

膜拜,用汇编语言编写的啊,看着就头大

wuyounanhai 发表于 2019-2-19 20:57

唉,是汇编语言不?

老刘 发表于 2019-2-19 21:51

wuyounanhai 发表于 2019-2-19 20:57
唉,是汇编语言不?

是汇编语言,就是跳转j**,判断cmp什么的用if,while,repeat代替了

jipinfeche 发表于 2019-2-19 21:53

膜拜大神 像天书一样什么也看不懂

菜鸟零号 发表于 2019-3-9 00:49

厉害,我目前还没有试验成功过关于显存的{:1_937:}

海天一色001 发表于 2019-4-16 08:25

正在学习算法,收下了,感谢楼主!
页: [1]
查看完整版本: [算法实战002]高精度正负浮点数四则运算