飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 3951|回复: 1

“无限”位四则运算

[复制链接]
  • TA的每日心情
    开心
    2019-9-19 16:05
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    发表于 2007-2-12 10:25:14 | 显示全部楼层 |阅读模式
    由于标准的数字变量类型取值有限,如果需要进行运算的数字超过了范围,用标准的数字变量类型就显得无能为力了!下面的四个函数利用Delphi中的字符串对象实现了大数运算。

    加法、乘法由zswang编写

    function StrLeft(const mStr: string; mDelimiter: string): string;
    begin
      Result := Copy(mStr, 1, Pos(mDelimiter, mStr) - 1);
    end; { StrLeft }

    function StrRight(const mStr: string; mDelimiter: string): string;
    begin
      if Pos(mDelimiter, mStr) <= 0 then
        Result := ''
      else Result := Copy(mStr, Pos(mDelimiter, mStr) + Length(mDelimiter), MaxInt);
    end; { StrRight }

    function formatnum(mNumber: string):string;
    var
      m:integer;
      TemStr:string;
    begin
      Result:='';
      for m:=1 to Length(mNumber) do
      begin
        if mNumber[m]='.' then
          Result:=Result+'.'
        else
          Result:=Result+IntToStr(StrToIntDef(mNumber[m], 0));
      end;
      while Pos('0', Result) = 1 do Delete(Result, 1, 1); //排除整数前无效的0
      if Pos('.', Result )<= 0 then Result := Result + '.'; //没有有小数点补小数点
      TemStr:=StrRight(Result,'.');
      while Copy(TemStr, Length(TemStr), 1) = '0' do Delete(TemStr, Length(TemStr), 1); //排除小数后无效的0
      Result:=StrLeft(Result,'.')+'.'+TemStr;
      if Copy(Result, Length(Result), 1) = '.' then Delete(Result, Length(Result), 1); //排除无效小数点
      if Copy(Result, 1, 1)='.' then Result:='0'+Result;
      if (Result = '') then Result := '0';
    end;

    function InfiniteAdd(mNumberA, mNumberB: string): string; { 无限位数加法 }
    var
      I: Integer;
      T: Integer;
    begin
      Result := '';
      if Pos('.', mNumberA) <= 0 then mNumberA := mNumberA + '.'; //没有有小数点补小数点
      if Pos('.', mNumberB) <= 0 then mNumberB := mNumberB + '.'; //没有有小数点补小数点
      I := Max(Length(StrLeft(mNumberA, '.')), Length(StrLeft(mNumberB, '.'))); //整数部分最大长度
      mNumberA := DupeString('0', I - Length(StrLeft(mNumberA, '.'))) + mNumberA; //整数前补0
      mNumberB := DupeString('0', I - Length(StrLeft(mNumberB, '.'))) + mNumberB; //整数前补0
      T := Max(Length(StrRight(mNumberA, '.')), Length(StrRight(mNumberB, '.'))); //小数部分最大长度
      mNumberA := mNumberA + DupeString('0', T - Length(StrRight(mNumberA, '.'))); //小数后补0
      mNumberB := mNumberB + DupeString('0', T - Length(StrRight(mNumberB, '.'))); //小数后补0
      I := I + T + 1; //计算总长度//小数长度和整数长度加上小数点长度
      T := 0; //进位数初始化
      for I := I downto 1 do //从后向前扫描
        if [mNumberA[I], mNumberB[I]] <> ['.'] then begin //不是小数点时
          T := StrToIntDef(mNumberA[I], 0) + T; //累加当前数位
          T := StrToIntDef(mNumberB[I], 0) + T; //累加当前数位
          Result := IntToStr(T mod 10) + Result; //计算当前数位上的数字
          T := T div 10; //计算进位数
        end else Result := '.' + Result; //加上小数点
      if T <> 0 then Result := IntToStr(T mod 10) + Result; //处理进位数
      while Pos('0', Result) = 1 do Delete(Result, 1, 1); //排除整数前无效的0
      while Copy(Result, Length(Result), 1) = '0' do
        Delete(Result, Length(Result), 1); //排除小数后无效的0
      if Copy(Result, Length(Result), 1) = '.' then
        Delete(Result, Length(Result), 1); //排除无效小数点
      if Copy(Result, 1, 1) = '.' then Result := '0' + Result; //处理无0小数情况
      if (Result = '') then Result := '0'; //处理空字符情况
    end; { InfiniteAdd }

    function InfiniteMult(mNumberA, mNumberB: string): string; { 无限位数乘法 }

      function fMult(mNumber: string; mByte: Byte): string; { 无限位数乘法子函数 }
      var
        I: Integer;
        T: Integer;
      begin
        Result := '';
        T := 0;
        for I := Length(mNumber) downto 1 do begin //从后向前扫描
          T := StrToIntDef(mNumber[I], 0) * mByte + T; //累加当前数位
          Result := IntToStr(T mod 10) + Result; //计算当前数位上的数字
          T := T div 10; //计算进位数
        end;
        if T <> 0 then Result := IntToStr(T mod 10) + Result; //处理进位数
      end; { fMult }

    var
      I: Integer;
      vDecimal: Integer; //小数位数
      T: string;
    begin
      Result := '';
      ///////Begin 处理小数
      if Pos('.', mNumberA) <= 0 then mNumberA := mNumberA + '.'; //没有有小数点补小数点
      if Pos('.', mNumberB) <= 0 then mNumberB := mNumberB + '.'; //没有有小数点补小数点
      vDecimal := Length(StrRight(mNumberA, '.')) + Length(StrRight(mNumberB, '.')); //计算小数位数
      mNumberA := StrLeft(mNumberA, '.') + StrRight(mNumberA, '.'); //删除小数点
      mNumberB := StrLeft(mNumberB, '.') + StrRight(mNumberB, '.'); //删除小数点
      ///////End 处理小数
      T := '';
      for I := Length(mNumberB) downto 1 do begin
        Result := InfiniteAdd(Result, fMult(mNumberA, StrToIntDef(mNumberB[I], 0)) + T);
        T := T + '0';
      end;
      Insert('.', Result, Length(Result) - vDecimal + 1);
      while Pos('0', Result) = 1 do Delete(Result, 1, 1); //排除整数前无效的0
      while Copy(Result, Length(Result), 1) = '0' do
        Delete(Result, Length(Result), 1); //排除小数后无效的0
      if Copy(Result, Length(Result), 1) = '.' then
        Delete(Result, Length(Result), 1); //排除无效小数点
      if Copy(Result, 1, 1) = '.' then Result := '0' + Result; //处理无0小数情况
      if (Result = '') then Result := '0'; //处理空字符情况
    end; { InfiniteMult }

    function InfiniteSub(mNumberA, mNumberB: string): string; { 无限位数减法 }
    var
      I: Integer;
      T: Integer;
      TemNumA:String;
      minus:Boolean;
    begin
      Result := '';
      mNumberA:=formatnum(mNumberA);
      mNumberB:=formatnum(mNumberB);
      if Pos('.', mNumberA) <= 0 then mNumberA := mNumberA + '.'; //没有有小数点补小数点
      if Pos('.', mNumberB) <= 0 then mNumberB := mNumberB + '.'; //没有有小数点补小数点
      I := Max(Length(StrLeft(mNumberA, '.')), Length(StrLeft(mNumberB, '.'))); //整数部分最大长度
      mNumberA := DupeString('0', I - Length(StrLeft(mNumberA, '.'))) + mNumberA; //整数前补0
      mNumberB := DupeString('0', I - Length(StrLeft(mNumberB, '.'))) + mNumberB; //整数前补0
      T := Max(Length(StrRight(mNumberA, '.')), Length(StrRight(mNumberB, '.'))); //小数部分最大长度
      if ((Length(StrLeft(mNumberA, '.'))) > (Length(StrLeft(mNumberB, '.')))) or(((Length(StrLeft(mNumberA, '.'))) = (Length(StrLeft(mNumberB, '.'))))and(mNumberB>mNumberA))then
      begin
        TemNumA := mNumberA;
        mNumberA := mNumberB + DupeString('0', T - Length(StrRight(mNumberB, '.'))); //小数后补0
        mNumberB := TemNumA + DupeString('0', T - Length(StrRight(TemNumA, '.'))); //小数后补0
        minus:=True;
      end
      else
      begin
        mNumberA := mNumberA + DupeString('0', T - Length(StrRight(mNumberA, '.'))); //小数后补0
        mNumberB := mNumberB + DupeString('0', T - Length(StrRight(mNumberB, '.'))); //小数后补0
        minus:=False;
      end;
      I := I + T + 1; //计算总长度//小数长度和整数长度加上小数点长度
      T := 0; //进位数初始化
      for I := I downto 1 do //从后向前扫描
        if [mNumberA[I], mNumberB[I]] <> ['.'] then begin //不是小数点时
          T := StrToIntDef(mNumberB[I], 0) - T; //累加当前数位
          T := StrToIntDef(mNumberA[I], 0) - T; //累加当前数位
          if (T<0) and (I<>1) then
          begin
            T:=T+10;
            Result := IntToStr(T mod 10) + Result; //计算当前数位上的数字
            T := -1; //计算进位数
          end
          else
          begin
            Result := IntToStr(T mod 10) + Result; //计算当前数位上的数字
            T := T div 10; //计算进位数
          end;
        end else Result := '.' + Result; //加上小数点
      if T <> 0 then Result := IntToStr(T mod 10) + Result; //处理进位数
      while Pos('0', Result) = 1 do Delete(Result, 1, 1); //排除整数前无效的0
      while Copy(Result, Length(Result), 1) = '0' do
        Delete(Result, Length(Result), 1); //排除小数后无效的0
      if Copy(Result, Length(Result), 1) = '.' then
        Delete(Result, Length(Result), 1); //排除无效小数点
      if Copy(Result, 1, 1) = '.' then Result := '0' + Result; //处理无0小数情况
      if (Result = '') then Result := '0'; //处理空字符情况
      if minus then Result:='-'+Result;
    end; { InfiniteSub}

    function InfiniteDiv(mNumberA, mNumberB: string;n:integer): string; { 无限位数除法 }
    //n为有效数字个数

    function vDecimal(mNumber: string):integer;
    var m,x:integer;
    begin
       x:=0;
       if Pos('.', mNumber) <= 0 then
       begin
         for m:=Length(mNumber) downto 1 do
         begin
           if mNumber[m]='0' then x:=x+1 else Break;
         end;
         Result:=-x;
       end
       else
         Result:=Length(StrRight(mNumber, '.'));
    end;

    function formatnum2(mNumber: string):string;
    begin
       Result:=mNumber;
       if Pos('.', Result )<= 0 then Result := Result + '.';
       Result:=StrLeft(Result,'.')+StrRight(Result,'.');
       while Pos('0', Result) = 1 do
         Delete(Result, 1, 1);//排除整数前无效的0
       while Copy(Result, Length(Result), 1) = '0' do
         Delete(Result, Length(Result), 1);//排除小数后无效的0
    end;

    var
      I,J,t,v,y,Len: Integer;
      TemSub,TemNum: string;
    begin
      Result := '';
      mNumberA:=formatnum(mNumberA);
      mNumberB:=formatnum(mNumberB);
      v:=vDecimal(mNumberA)-vDecimal(mNumberB);
      mNumberA:=formatnum2(mNumberA);
      mNumberB:=formatnum2(mNumberB);
      if mNumberB='' then
        Result:='Err'
      else if mNumberA='' then
        Result:='0'
      else
      begin
      I:=0;
      if Length(mNumberA)>Length(mNumberB) then
        Len:=Length(mNumberB)
      else
        Len:=Length(mNumberA);
      if Copy(mNumberA,1,Len)>=Copy(mNumberB,1,Len) then
        J:=Length(mNumberB)
      else
        J:=Length(mNumberB)+1;
      for y:=1 to J do
      begin
        if Length(mNumberA)>=y then
          TemSub:=TemSub+mNumberA[y]
        else
        begin
          TemSub:=TemSub+'0';
          v:=v+1;
        end;
      end;
      while I<=n-1 do
      begin
        if TemSub[1]>mNumberB[1] then
          t:=StrToInt(TemSub[1]) Div StrToInt(mNumberB[1])
        else
          t:=StrToInt(TemSub[1]+TemSub[2]) Div StrToInt(mNumberB[1]);
        TemNum:=InfiniteMult(mNumberB,IntToStr(t));
        while (Length(TemNum)>Length(TemSub)) or ((Length(TemNum)=Length(TemSub))and(TemNum>TemSub)) do
        begin
          t:=t-1;
          TemNum:=InfiniteMult(mNumberB,IntToStr(t));
        end;
        Result:=Result+IntToStr(t);
        I:=I+1;
        TemSub:=InfiniteSub(TemSub,TemNum);
        if (TemSub='0') and (Length(mNumberA)<J) then
        begin
          v:=v+1;
          Break;
        end;
        if TemSub='0' then TemSub:='';
        J:=J+1;
        if Length(mNumberA)>=J then
        begin
          TemSub:=TemSub+mNumberA[J];
        end
        else
        begin
          TemSub:=TemSub+'0';
          v:=v+1;
        end;
      end;
      if Length(mNumberA)>=J then
        v:=v-(Length(mNumberA)-J)-1
      else
        v:=v-1;
      while Copy(Result, Length(Result), 1) = '0' do
      begin
        v:=v-1;
        Delete(Result, Length(Result), 1);
      end;
      if v>Length(Result) then
        Result:='.'+DupeString('0',v-Length(Result)) + Result
      else if v>0 then
        Insert('.', Result, Length(Result) - v +1); //插入小数点
      if v<0 then Result:=Result+DupeString('0',0-v);
      if Copy(Result, 1, 1)='.' then Result:='0'+Result; //小数前面补0
      end;
    end; { InfiniteDiv}

    一时消遣娱乐之作~~~
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2007-2-12 12:59:17 | 显示全部楼层
    大数运算,需要由数组来模拟了。。。。。。。。
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表