Flutter Dart BigDecimal

目录

前言

Dart中只有BigInt没有BigDecimal,所以需要手动去实现BigDecimal。

如果我的代码帮到你,请给我点个赞。

API

构造函数

  • BigDecimal([dynamic number]) 将任意toString后能表示为小数的类型转换为BigDecimal
  • BigDecimal.fromReal(List real) 将BigDecimal实数部分转换为BigDecimal
  • BigDecimal.fromDecimal(List decimal) 将BigDecimal小数部分转换为BigDecimal

四则及幂运算

  • BigDecimal operator + (dynamic number)
  • BigDecimal operator - (dynamic number)
  • BigDecimal operator * (dynamic number)
  • BigDecimal operator / (dynamic number)
  • BigDecimal pow(int n) 快速幂运算

其他

  • BigDecimal disablePrecisionLimit() 取消除法运算精度,可能导致程序无限循环进行除法运算
  • BigDecimal setDivMaxPrecision(int precision) 设置除法运算最大的精度,默认1000
  • BigDecimal clone() 克隆BigDecimal对象
  • BigDecimal abs() 取正
  • List real() 获取实数部分
  • List decimal() 获取小数部分

代码

BigDecimal.dart

dart 复制代码
import 'dart:math' as Math;

//TODO StringBuilder自己想办法解决
import 'package:module_utils/tools/StringBuilder.dart';

///高精度大数
///
/// eg: [123][1][2][3].[123][1][123] => 123 000000001 000000002 000000003.000000123 000000001 000000123
class BigDecimal{

  static get nan  => BigDecimal("nan");
  static get zero => BigDecimal("0.0");
  static get one  => BigDecimal("1.0");
  static get two  => BigDecimal("2.0");


  //实数部分 非空 [高位,低位] 值∈[0, 1E9-1]
  final List<int> _real = [];
  //小数部分 非空 [高位,低位] 值∈[0, 1E9-1]
  final List<int> _decimal = [];

  //正负号 true:+ false:-
  bool _sign = true;

  //无穷大 除数为0时,商为无穷大
  bool _nan  = false;


  //sqrt(int.max = 9223372036854775807) = 3037000499
  //每个list元素最大的值 1E10 - 1
  static const int _MaxUnit = 999999999;
  static const int _1E9    = 1000000000;

  static BigDecimal min(BigDecimal b1, BigDecimal b2){
    return b1<b2 ? b1 : b2;
  }

  static BigDecimal max(BigDecimal b1, BigDecimal b2){
    return b1<b2 ? b2 : b1;
  }

  static int _lengthOfNormal([int num]) => 9;

  //求实数最高元素的位数长度 eg: 123456 => 6
  static int _lengthOfReal(int num){
    return _splitReal(num).length;
  }

  //求小数最低元素的位数长度 eg: 1234560 = 00123456 => 8
  static int _lengthOfDecimal(int num){
    return _splitDecimal(num).length;
  }

  //将整数拆分 eg: 123456 => [0,0,0,1,2,3,4,5,6]
  static List<int> _splitNormal(int num){
    return List.filled(9, 1).asMap().keys.map((e) => num~/Math.pow(10,e)%10).toList().reversed.toList();
  }

  //将实数高位元素拆分 eg: 123456 => [1,2,3,4,5,6]
  static List<int> _splitReal(int num){
    return List.filled(9, 1).asMap().keys.map((e) => num~/Math.pow(10,e)%10).toList().reversed.skipWhile((value) => value==0).toList();
  }

  //将小数低位元素拆分 eg: 123456000 => [1,2,3,4,5,6] err:0000100000
  static List<int> _splitDecimal(int num){
    return num == 0 ? [0] :List.filled(9, 1).asMap().keys.map((e) => num~/Math.pow(10,e)%10).toList().skipWhile((value) => value==0).toList().reversed.toList();
  }

  //将整数数组拆分 eg: [123,456,789] => [0,0,0,0,0,0,1,2,3,0,0,0,0,0,0,4,5,6,0,0,0,0,0,0,7,8,9]
  static List<int> __splitNormal(List<int> numbers){
    return numbers.map((e) => _splitNormal(e)).expand((e) => e).toList();
  }

  //将实数元素数组拆分 eg: [123,456,7890] => [1,2,3,0,0,0,0,0,0,4,5,6,0,0,0,0,0,7,8,9,0]
  static List<int> __splitReal(List<int> numbers){
    return __splitNormal(numbers).skipWhile((value) => value==0).toList();
  }
  //将小数元素数组拆分 eg: [123,456,7890] => [0,0,0,0,0,0,1,2,3,0,0,0,0,0,0,4,5,6,0,0,0,0,0,7,8,9]
  static List<int> __splitDecimal(List<int> numbers){
    var result = __splitNormal(numbers);
    for(int i=result.length-1; i>0; --i){
      if(result[i] == 0) result.removeLast();
      else break;
    }
    return result;
  }

  //将按位分割的整数数组组合成一个整数 eg: [1,2,3,4,5,6] => 123456
  static int _combineNormal(List<int> numbers){
    return int.parse(numbers.join());
  }

  //将按位分割的整数数组组合成一个实数高位元素 eg: [0,1,2,3,4,5,6] => 123456
  static int _combineReal(List<int> numbers){
    return int.parse(numbers.skipWhile((e) => e==0).join().padLeft(1,"0"));
  }

  //将按位分割的整数数组组合成一个小数低位元素 eg: [1,2,3,4,5,6] => 123456000
  static int _combineDecimal(List<int> numbers){
    return numbers.length==1&&numbers[0]==0 ? 0 : int.parse(numbers.join().padRight(9,"0"));
  }

  //将按位分割的整数数组组组合成大数实数元素数组 eg: [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7] => [12345678,901234567]
  static List<int> __combineReal(List<int> numbers){
    List<int> nums = numbers.skipWhile((e) => e==0).toList();
    return List.filled(nums.length~/10 + (nums.length%10==0?0:1), 0)
        .asMap()
        .keys
        .map((e) => _combineReal(nums.sublist(Math.max(0,nums.length-(10*(e+1))), nums.length-(10*e))))
        .toList();
  }

  //将按位分割的整数数组组组合成大数小数元素数组 eg: [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7] => [123456789,12345670]
  static List<int> __combineDecimal(List<int> numbers){
    var nums = []..addAll(numbers);
    while(nums.length%10 != 0) nums.add(0);

    return List.filled(nums.length~/10 + (nums.length%10==0?0:1), 0)
        .asMap()
        .keys
        .map(
            (e) =>
        		e==(nums.length~/10-1)
            	? _combineDecimal(nums.sublist(10*e, Math.min(10*(e+1), nums.length)))
            	: _combineReal   (nums.sublist(10*e, 10*(e+1)))
    	)
        .toList();
  }

  static List<int> _parseReal(String part){
    List<int> result = [];
    while(part.length>0){
      int length = part.length;
      int index  = Math.max(length-9, 0);
      int num    = int.parse(part.substring(index, part.length));
      part   = part.substring(0, index);
      result.insert(0,num);
    }
    if(result.isEmpty) result.add(0);
    return result;
  }

  static List<int> _parseDecimal(String part){
    List<int> result = [];
    while(part.length>0){
      int length = part.length;
      int index  = Math.min(length, 9);
      int num    = int.parse(part.substring(0,index).padRight(9,"0"));
      part   = part.substring(index);
      result.add(num);
    }
    if(result.isEmpty) result.add(0);
    return result;
  }

  BigDecimal.fromReal(List<int> real){
    _real   .addAll(real);
    _decimal.add(0);
  }

  BigDecimal.fromDecimal(List<int> decimal){
    _real   .add(0);
    _decimal.addAll(decimal);
  }

  BigDecimal([dynamic number]){
    try{
      if(number == null) return;
      if(number is BigDecimal){
        _real.addAll(number._real);
        _decimal.addAll(number._decimal);
        _sign = number._sign;
        _nan  = number._nan;
        return;
      }
      if(number is double){
        if(number.isNaN){
          _nan  = true;
          return;
        }
        BigDecimal decimal = BigDecimal(number.toString());
        _real.addAll(decimal._real);
        _decimal.addAll(decimal._decimal);
        _sign = decimal._sign;
        _nan  = decimal._nan;
        return;
      }
      if(number is int) {
        _sign = number>-1;
        _real.add(number.abs());
        _nan  = number.isNaN;
        return;
      }

      String strNumber = number.toString().trim();
      if(strNumber.toLowerCase() == "nan"){
        _sign = true;
        _nan  = true;
        return;
      }
      _nan = false;
      String num = "";
      //判断正负号
      for(int i=0,ni=strNumber.length; i<ni; ++i){
        if(strNumber.codeUnitAt(i)=='-'.codeUnitAt(0)){
          _sign = false;
          break;
        }
        if(strNumber.codeUnitAt(i)=='.'.codeUnitAt(0)){
          _sign = true;
          break;
        }
        if(strNumber.codeUnitAt(i)>='0'.codeUnitAt(0) && strNumber.codeUnitAt(i)<='9'.codeUnitAt(0)){
          _sign = true;
          break;
        }
      }

      //格式化
      for(int i=0,ni=strNumber.length; i<ni; ++i){
        if(strNumber.codeUnitAt(i)>='0'.codeUnitAt(0) && strNumber.codeUnitAt(i)<='9'.codeUnitAt(0)){
          num += strNumber.substring(i,i+1);
        }
        if(strNumber.codeUnitAt(i)=='.'.codeUnitAt(0) && num.indexOf(".")<0){
          num += strNumber.substring(i,i+1);
        }
      }
      if(num.length == 0) num = "0.0";
      else if(num.indexOf(".")<0) num = num+".0";

      int index = num.indexOf(".");
      String strR = num.substring(0, index);
      String strD = num.substring(index+1);
      _real   .addAll(_parseReal   (strR));
      _decimal.addAll(_parseDecimal(strD));
    }
    finally{
      if(_real   .isEmpty) _real   .add(0);
      if(_decimal.isEmpty) _decimal.add(0);
    }
  }

  int compare(BigDecimal another){
    if(_nan && !another._nan) return  1;
    if(!_nan && another._nan) return -1;
    if(_sign && !another._sign) return  1;
    if(!_sign && another._sign) return -1;

    bool sign = _sign;

    //判断实数部分
    if(_real.length > another._real.length) return sign ?  1 : -1;
    if(_real.length < another._real.length) return sign ? -1 :  1;
    for(int i=0,ni=_real.length; i<ni; ++i){
      if(_real[i]>another._real[i]) return sign ?  1 : -1;
      if(_real[i]<another._real[i]) return sign ? -1 :  1;
    }
    //以下实数部分相等

    //判断小数部分
    //判断高位
    for(int i=0, ni=Math.min(_decimal.length, another._decimal.length)-1; i<ni;++i){
      if(_decimal[i]>another._decimal[i]) return sign ?  1 : -1;
      if(_decimal[i]<another._decimal[i]) return sign ? -1 :  1;
    }
    //将整数各个位分割以便判断低位
    int index = Math.min(_decimal.length, another._decimal.length)-1;
    List<int> num1 = List.filled(10, 1).asMap().keys.map((e) =>         _decimal[index]~/Math.pow(10,e)%10).toList().reversed.toList();
    List<int> num2 = List.filled(10, 1).asMap().keys.map((e) => another._decimal[index]~/Math.pow(10,e)%10).toList().reversed.toList();
    for(int i=0,ni=Math.min(num1.length, num2.length); i<ni;++i){
      if(num1[i]>num2[i]) return sign ?  1 : -1;
      if(num1[i]<num2[i]) return sign ? -1 :  1;
    }
    if(num1.length>num2.length) return sign ?  1 : -1;
    if(num2.length<num2.length) return sign ? -1 :  1;

    if(_decimal.length > another._decimal.length) return sign ?  1 : -1;
    if(_decimal.length < another._decimal.length) return sign ? -1 :  1;
    return 0;
  }

  bool operator <  (dynamic number) => this.compare(BigDecimal(number)) == -1;

  bool operator >  (dynamic number) => this.compare(BigDecimal(number)) ==  1;

  bool operator == (dynamic number) => this.compare(BigDecimal(number)) ==  0;

  BigDecimal operator + (dynamic number){
    BigDecimal another = BigDecimal(number);
    if(_nan | another._nan) return nan;

    //符号不一致
    if(_sign ^ another._sign){
      //当做减法处理
      if(_sign) return this - another.abs();
      return another - abs();
    }

    //符号一致处理
    //region 小数部分
    List<int> dec1 = _decimal;
    List<int> dec2 = another._decimal;
    int decLen1 = dec1.length;
    int decLen2 = dec2.length;
    //  计算小数公共元素的长度
    int decCommonLen = Math.min(decLen1, decLen2);
    //  小数计算结果存放
    List<int> decSum = []..addAll(dec1.sublist(decCommonLen))
      ..addAll(dec2.sublist(decCommonLen));
    //  进位标记
    bool carry = false;
    //  小数公共元素数组求和
    for(int i=decCommonLen-1; i>-1; --i){
      int sum =  dec1[i] + dec2[i] + (carry?1:0);
      carry = sum >= _1E9;
      if(carry) sum = sum%_1E9;
      decSum.insert(0, sum);
    }
    // 小数格式化
    for(int i=decSum.length-1; i>0; --i){
      if(decSum[i]==0) decSum.removeLast();
      else break;
    }
    //endregion

    //region 实数部分
    List<int> real1 =         _real;
    List<int> real2 = another._real;
    int realLen1 = real1.length;
    int realLen2 = real2.length;
    List<int> realSum = [];
    //  公共部分求和
    for(int i=realLen1-1, j=realLen2-1; j>-1||i>-1; --i,--j){
      int sum =(i<0?0:real1[i]) + (j<0?0:real2[j]) + (carry?1:0);
      carry = sum >= _1E9;
      if(carry) sum = sum%_1E9;
      realSum.insert(0, sum);
    }
    if(carry) realSum.insert(0, 1);
    //endregion

    return BigDecimal()
      .._nan = false
      .._sign = _sign
      .._real.clear()
      .._real.addAll(realSum)
      .._decimal.clear()
      .._decimal.addAll(decSum);
  }

  BigDecimal operator - (dynamic number){
    BigDecimal another = BigDecimal(number);
    if(_nan | another._nan) return nan;

    //符号不一致
    if(_sign ^ another._sign){
      //当做加法处理
      if(_sign) return this + another.abs();
      return (abs() + another.abs()).._sign = false;
    }


    //符号一致且都是正数
    if(_sign){
      //减不过就换位减
      if(this < another){
        return (another - this).._sign = false;
      }
    }
    //符号一致且都是负数
    else{
      //-a - -b  =>  b - a
      return another.abs() - abs();
    }

    bool borrow = false;
    //region 小数部分
    List<int> dec1 =         _decimal;
    List<int> dec2 = another._decimal;
    int decLen1 = dec1.length;
    int decLen2 = dec2.length;
    List<int> decSub = [];
    //  求差
    for(int i=Math.max(decLen1,decLen2)-1; i>-1; --i){
      int num1 = i < decLen1 ? dec1[i] : 0;
      int num2 = i < decLen2 ? dec2[i] : 0;
      int sub = num1 - num2 - (borrow?1:0);
      borrow = sub<0;
      if(borrow) sub += _1E9;
      decSub.insert(0, sub);
    }
    // 小数格式化
    for(int i=decSub.length-1; i>0; --i){
      if(decSub[i]==0) decSub.removeLast();
      else break;
    }
    //endregion

    //region 实数部分
    List<int> real1 =         _real;
    List<int> real2 = another._real;
    int realLen1 = real1.length;
    int realLen2 = real2.length;
    List<int> realSub = [];
    //  求差
    for(int idx1=realLen1-1, idx2=realLen2-1, i=Math.max(realLen1, realLen2); i>0; --i,--idx1,--idx2){
      int sub = (idx1<0?0:real1[idx1]) - (idx2<0?0:real2[idx2]) - (borrow?1:0);
      borrow = sub<0;
      if(borrow) sub += _1E9;
      realSub.insert(0, sub);
    }
    // 实数格式化
    for(int i=0, ni=realSub.length-1; i<ni; ++i){
      if(realSub[0]==0) realSub.removeAt(0);
      else break;
    }
    //endregion

    return BigDecimal()
      .._nan = false
      .._sign = !borrow
      .._real.clear()
      .._real.addAll(realSub)
      .._decimal.clear()
      .._decimal.addAll(decSub);
  }

  BigDecimal operator * (dynamic number){
    BigDecimal another = BigDecimal(number);
    if(_nan | another._nan) return nan;
    if(this == zero || another == zero) return zero;
    if(this == one) return another;
    if(another == one) return this.clone();

    //将两个数拆分成位数组
    List<int> dec1 =         _decimal;
    List<int> dec2 = another._decimal;
    int decLen1 = dec1.length;
    int decLen2 = dec2.length;
    int decMulLen = decLen1 + decLen2;
    List<int> real1 =         _real;
    List<int> real2 = another._real;
    List<int> num1 = []..addAll(real1)..addAll(dec1);
    List<int> num2 = []..addAll(real2)..addAll(dec2);
    int numLen1 = num1.length;
    int numLen2 = num2.length;
    int numMulLen = numLen1 + numLen2;//可能的最大长度
    //计算结果
    List<int> numMul = List.filled(numMulLen+1, 0);
    Function(int, int) add = (int index, int number){
      numMul[index] += number;
      int carry = numMul[index]~/_1E9;
      while(carry>0){
        numMul[index] %= _1E9;
        numMul[--index] += carry;
        carry = numMul[index]~/_1E9;
      }
    };
    for(int i=numLen2-1, idx2=0, idx3=numMulLen; i>-1; --i,++idx2,idx3=numMulLen-idx2){
      for(int j=numLen1-1, idx1=numMulLen-1-idx2; j>-1; --j,--idx1,--idx3){
        int mul = num2[i]*num1[j];
        add(idx3, mul);
      }
    }
    List<int> real    = numMul.sublist(0                          , numMul.length - decMulLen);
    List<int> decimal = numMul.sublist(numMul.length - decMulLen);
    while(real.length>1){
      if(real[0]==0) real.removeAt(0);
      else break;
    }
    // 小数格式化
    for(int i=decimal.length-1; i>0; --i){
      if(decimal[i]==0) decimal.removeLast();
      else break;
    }
    return BigDecimal()
      .._sign = !(_sign ^ another._sign)
      .._nan = false
      .._real.clear()
      .._real.addAll(real)
      .._decimal.clear()
      .._decimal.addAll(decimal);
  }

  BigDecimal operator / (dynamic number){
    BigDecimal another = BigDecimal(number);
    if(_nan | another._nan) return nan;
    if(this == zero) return zero;
    if(another == zero) return nan;
    //将两个数拆分成元素数组
    List<int> dec1 =         _decimal;
    List<int> dec2 = another._decimal;
    List<int> real1 =         _real;
    List<int> real2 = another._real;
    List<int> num1 = []..addAll(real1)..addAll(dec1);
    List<int> num2 = []..addAll(real2)..addAll(dec2);
    //初始化除数的倍数
    final Map<int, BigDecimal> mTimes = {0:BigDecimal.zero, 1:BigDecimal.fromReal(num2)};
    Function(BigDecimal, BigDecimal) add = (num1,num2) => BigDecimal.fromReal((num1+num2)._real);
    Function(int) timesOfDivisor;
    timesOfDivisor = (time){
      BigDecimal value = mTimes[time];
      if(value != null) return value;
      value = add(timesOfDivisor(time~/2 + (time%2==0?0:1)), timesOfDivisor(time~/2));
      mTimes[time] = value;
      return value;
    };

    //region 二分减法
    //b1~/b2 => [quotient, remainder]
    Function(BigDecimal, BigDecimal) binSub = (BigDecimal b1, BigDecimal b2){
      //平均计算 log2(10)≈3   log2(1E9)≈30
      //                    0 9 => 5
      //       0 4 => 2                  6 9 => 7
      //0 2 => 1     3 4 => 3      6 7 => 6    8 9 => 8
      // 0 1 2          3 4     5     6 7        8 9

      int l = 0, r = _MaxUnit;
      while(l<r){
        int m = (l+r)~/2;
        BigDecimal b3 = timesOfDivisor(m);
        int comp = b1.compare(b3);
        if(comp == 0) return [m,[0]];

        //b1 > b3 m可能是结果
        if(comp == 1){
          if(l+1 == r){
            BigDecimal b4 = timesOfDivisor(r);
            comp = b1.compare(b4);
            if(comp == 0) return [r,[0]];
            if(comp == 1) return [r,(b1-b4)._real];
            return [l,(b1-b3)._real];
          }
          l = m;
          continue;
        }
        //b1 < b3 m一定不是结果
        if(l+1 == r) return [m,(b1-b3)._real];
        r = m - 1;
      }
      //一定不会执行此语句

      return [l,(b1-timesOfDivisor(l))._real];
    };
    //endregion

    //求商
    List<int> numDiv = [];
    int nRealPrecision = real1.length+dec2.length;
    int pPrecision = -nRealPrecision;
    List<int>  dividend = [];
    List<int>  divisor = num2;
    BigDecimal bdDivisor  = BigDecimal.fromReal(num2);
    int divMaxBitPrecision = _divMaxPrecision<0?-1:_divMaxPrecision~/9 + (_divMaxPrecision%9==0?0:1);
    for(int i=0; i<num1.length||dividend.isNotEmpty; ++i){
      if(divMaxBitPrecision>-1){
        if(pPrecision>=divMaxBitPrecision) break;
      }
      // print("#${i.toString().padLeft(4,"0")}: [${dividend.length}]:$dividend");
      ++pPrecision;
      int num = i<num1.length?num1[i]:0;
      if(num!=0 || dividend.isNotEmpty) dividend.add(num);

      //不够减
      if(dividend.length<divisor.length) {
        numDiv.add(0);
        continue;
      }
      BigDecimal bdDividend = BigDecimal.fromReal(dividend);
      List       result     = binSub(bdDividend, bdDivisor);
      int        quotient   = result[0];
      List<int>  remainder  = result[1];
      numDiv.add(quotient);
      if(quotient == 0) continue;
      dividend.clear();
      dividend.addAll(remainder.skipWhile((e) => e==0).toList());
    }

    List<int> divReal    = numDiv.sublist(0             , nRealPrecision).skipWhile((e) => e==0).toList();
    List<int> divDecimal = numDiv.sublist(nRealPrecision);
    if(divReal   .isEmpty) divReal   .add(0);
    if(divDecimal.isEmpty) divDecimal.add(0);
    //精度对齐
    if(_divMaxPrecision>-1&&_divMaxPrecision%9!=0){
      int last = divDecimal.last;
      int len  = _divMaxPrecision%9;
      List<int> llast = _splitDecimal(last);
      llast = llast.sublist(0, Math.min(llast.length, len));
      divDecimal.removeLast();
      divDecimal.add(_combineDecimal(llast));
    }
    for(int i=divDecimal.length-1; i>0; --i){
      if(divDecimal[i]==0) divDecimal.removeLast();
      else break;
    }

    return BigDecimal()
      .._sign = !(_sign ^ another._sign)
      .._nan = false
      .._real.clear()
      .._real.addAll(divReal)
      .._decimal.clear()
      .._decimal.addAll(divDecimal);
  }

  //为了防止计算除法时出现无限小数,设置此位防止死循环
  //负数代表不限制
  int _divMaxPrecision = 1000;
  BigDecimal setDivMaxPrecision(int precision){
    _divMaxPrecision = precision;
    return this;
  }
  BigDecimal disablePrecisionLimit(){
    _divMaxPrecision = -1;
    return this;
  }

  List<int> real   () => __splitReal   (_real   );

  List<int> decimal() => __splitDecimal(_decimal);

  BigDecimal _powInternal(int n, Map<int,BigDecimal> mPow){
    BigDecimal bd = mPow[n];
    if(bd!=null) return bd;
    int p1 = n~/2;
    int p2 = p1 + (n%2==0?0:1);
    BigDecimal bdPow = _powInternal(p1, mPow)*_powInternal(p2, mPow);
    mPow[n] = bdPow;
    return bdPow.clone();
  }

  BigDecimal pow(int n){
    return _powInternal(n, {0:BigDecimal.one,1:clone()});
  }

  BigDecimal clone() => BigDecimal()
    .._nan = false
    .._sign = _sign
    .._real.clear()
    .._real.addAll(_real)
    .._decimal.clear()
    .._decimal.addAll(_decimal);

  BigDecimal abs(){
    return BigDecimal()
      .._sign = true
      .._nan = _nan
      .._real.clear()
      .._real.addAll(_real)
      .._decimal.clear()
      .._decimal.addAll(_decimal);
  }

  @override
  String toString(){
    if(_nan) return "nan";
    StringBuilder sb = StringBuilder();
    if(!_sign) sb.append("-");
    sb.append(_real[0].toString());
    for(int i=1,ni=_real.length;i<ni;++i){
      sb.append(_real[i].toString().padLeft(9,'0'));
    }
    sb.append(".");
    if(_decimal.length>1) {
      for(int i=0,ni=_decimal.length-1;i<ni;++i){
        sb.append(_decimal[i].toString().padLeft(9,'0'));
      }
    }
    sb.append(_splitDecimal(_decimal[_decimal.length-1]).join());

    return sb.toString();
  }

  @override
  int get hashCode => _real.hashCode * _decimal.hashCode;
}

bigdecimal_test.dart

dart 复制代码
import 'dart:math';

import 'package:flutter_test/flutter_test.dart';

import 'BigDecimal.dart';
import 'StringBuilder.dart';

//region randomGenerate
Random random = Random(DateTime.now().millisecondsSinceEpoch);
String generateNumber({bool decimal=false, int length=0, int maxLength=10000}){
  while(length==0) length = random.nextInt(maxLength+1);

  StringBuilder sb = StringBuilder();
  while(sb.length() < length){
    int num = random.nextInt(min(0x7fffffff,pow(10,min(10,length-sb.length()))));
    sb.append(num.toString());
  }
  if(decimal){
    if(sb.charAt(sb.length()-1) == "0".codeUnitAt(0)){
      int num = random.nextInt(10);
      while(num==0) num = random.nextInt(10);
      sb.replace(sb.length()-1, sb.length(), num.toString());
    }
  }
  else{
    if(sb.charAt(0) == "0".codeUnitAt(0)){
      int num = random.nextInt(10);
      while(num==0) num = random.nextInt(10);
      sb.replace(0, 1, num.toString());
    }
  }
  return sb.toString();
}
//endregion

void main(){
  test("BigDecimal constructor test", ()async{
    //验证nan
    print("Testing NAN");
    expect(BigDecimal("nan").toString()=="nan" , isTrue);
    //验证1,1E10,1E100,1E1000,1E10000
    print("Testing Positive");
    expect(BigDecimal("1".padRight(pow(10, 0)+1,"0")).toString(), "1".padRight(pow(10, 0)+1,"0")+".0");
    expect(BigDecimal("1".padRight(pow(10, 1)+1,"0")).toString(), "1".padRight(pow(10, 1)+1,"0")+".0");
    expect(BigDecimal("1".padRight(pow(10, 2)+1,"0")).toString(), "1".padRight(pow(10, 2)+1,"0")+".0");
    expect(BigDecimal("1".padRight(pow(10, 3)+1,"0")).toString(), "1".padRight(pow(10, 3)+1,"0")+".0");
    expect(BigDecimal("1".padRight(pow(10, 4)+1,"0")).toString(), "1".padRight(pow(10, 4)+1,"0")+".0");
    //验证1E-1,1E-10,1E-100,1E-1000,1E-10000
    print("Testing Negative");
    expect(BigDecimal("0.${"1".padLeft(pow(10, 0),"0")}").toString(), "0.${"1".padLeft(pow(10, 0),"0")}");
    expect(BigDecimal("0.${"1".padLeft(pow(10, 1),"0")}").toString(), "0.${"1".padLeft(pow(10, 1),"0")}");
    expect(BigDecimal("0.${"1".padLeft(pow(10, 2),"0")}").toString(), "0.${"1".padLeft(pow(10, 2),"0")}");
    expect(BigDecimal("0.${"1".padLeft(pow(10, 3),"0")}").toString(), "0.${"1".padLeft(pow(10, 3),"0")}");
    expect(BigDecimal("0.${"1".padLeft(pow(10, 4),"0")}").toString(), "0.${"1".padLeft(pow(10, 4),"0")}");
    //随机测验实数和小数长度[1,10000]
    print("Testing Random");
    for(int i=0;i<10000;++i){
      bool   sign    = random.nextBool();
      String real    = generateNumber(decimal: false);
      String decimal = generateNumber(decimal: true );
      String number  = "${sign?"":"-"}$real.$decimal";
      print("\tEvaluating #${i.toString().padLeft(4)} ${sign?" ":"-"}[${real.length.toString().padLeft(5)}].[${decimal.length.toString().padLeft(5)}]:$number");
      expect(BigDecimal(number).toString(), number, reason: "Compare error $i: ${sign?" ":""}$number");
    }
    print("Test passed!!!");
  },timeout: Timeout(Duration(minutes: 1)));

  test("BigDecimal compare test", ()async{
    expect(BigDecimal("-1").compare(BigDecimal("1" )), -1);
    expect(BigDecimal("1" ).compare(BigDecimal("-1")),  1);
    expect(BigDecimal("1" ).compare(BigDecimal("1" )),  0);
    //Test 99...9 10....0
    expect(BigDecimal("9".padLeft (10   ,"9")).compare(BigDecimal("1".padRight(11   ,"0"))), -1);
    expect(BigDecimal("1".padRight(11   ,"0")).compare(BigDecimal("9".padLeft (10   ,"9"))),  1);
    expect(BigDecimal("9".padLeft (100  ,"9")).compare(BigDecimal("1".padRight(101  ,"0"))), -1);
    expect(BigDecimal("1".padRight(101  ,"0")).compare(BigDecimal("9".padLeft (100  ,"9"))),  1);
    expect(BigDecimal("9".padLeft (1000 ,"9")).compare(BigDecimal("1".padRight(1001 ,"0"))), -1);
    expect(BigDecimal("1".padRight(1001 ,"0")).compare(BigDecimal("9".padLeft (1000 ,"9"))),  1);
    expect(BigDecimal("9".padLeft (10000,"9")).compare(BigDecimal("1".padRight(10001,"0"))), -1);
    expect(BigDecimal("1".padRight(10001,"0")).compare(BigDecimal("9".padLeft (10000,"9"))),  1);
    //Test -99...9 -10....0
    expect(BigDecimal("-${"9".padLeft (10   ,"9")}").compare(BigDecimal("-${"1".padRight(11   ,"0")}")),  1);
    expect(BigDecimal("-${"1".padRight(11   ,"0")}").compare(BigDecimal("-${"9".padLeft (10   ,"9")}")), -1);
    expect(BigDecimal("-${"9".padLeft (100  ,"9")}").compare(BigDecimal("-${"1".padRight(101  ,"0")}")),  1);
    expect(BigDecimal("-${"1".padRight(101  ,"0")}").compare(BigDecimal("-${"9".padLeft (100  ,"9")}")), -1);
    expect(BigDecimal("-${"9".padLeft (1000 ,"9")}").compare(BigDecimal("-${"1".padRight(1001 ,"0")}")),  1);
    expect(BigDecimal("-${"1".padRight(1001 ,"0")}").compare(BigDecimal("-${"9".padLeft (1000 ,"9")}")), -1);
    expect(BigDecimal("-${"9".padLeft (10000,"9")}").compare(BigDecimal("-${"1".padRight(10001,"0")}")),  1);
    expect(BigDecimal("-${"1".padRight(10001,"0")}").compare(BigDecimal("-${"9".padLeft (10000,"9")}")), -1);
    //Test random
    for(int i=0; i<10000; ++i){
      bool   sign1       = random.nextBool();
      String strReal1    = generateNumber(decimal: false);
      String strDecimal1 = generateNumber(decimal: true );
      String number1     = "${sign1?"":"-"}$strReal1.$strDecimal1";

      bool   sign2       = random.nextBool();
      String strReal2    = generateNumber(decimal: false);
      String strDecimal2 = generateNumber(decimal: true );
      String number2     = "${sign2?"":"-"}$strReal2.$strDecimal2";

      int compare;
      if( sign1 && !sign2) compare =  1;
      if(!sign1 &&  sign2) compare = -1;
      if(sign1 == sign2){
        bool sign = sign1;
        if     (strReal1.length>strReal2.length) compare =  1;
        else if(strReal1.length<strReal2.length) compare = -1;
        else compare = strReal1.compareTo(strReal2);
        if(compare==0){
          String strDecimal3 = strDecimal1.padRight(max(strDecimal1.length, strDecimal2.length),"0");
          String strDecimal4 = strDecimal2.padRight(max(strDecimal1.length, strDecimal2.length),"0");
          compare = strDecimal3.compareTo(strDecimal4);
        }
        if(compare!=0){
          compare = sign ? compare : -compare;
        }
      }

      expect(BigDecimal(number1).compare(BigDecimal(number2)), compare);
    }
  });

  test("BigDecimal operator + test", ()async{
    print("Testing Basic");
    expect((BigDecimal("1" )+BigDecimal("1" )).toString(), BigDecimal("2" ).toString());
    expect((BigDecimal("-1")+BigDecimal("1" )).toString(), BigDecimal.zero .toString());
    expect((BigDecimal("-1")+BigDecimal("-1")).toString(), BigDecimal("-2").toString());

    print("Testing Real");
    expect((BigDecimal("9".padLeft (10   ,"9"))+BigDecimal.one).toString(), BigDecimal("1".padRight(11   ,"0")).toString());
    expect((BigDecimal("9".padLeft (100  ,"9"))+BigDecimal.one).toString(), BigDecimal("1".padRight(101  ,"0")).toString());
    expect((BigDecimal("9".padLeft (1000 ,"9"))+BigDecimal.one).toString(), BigDecimal("1".padRight(1001 ,"0")).toString());
    expect((BigDecimal("9".padLeft (10000,"9"))+BigDecimal.one).toString(), BigDecimal("1".padRight(10001,"0")).toString());

    print("Testing Decimal");
    expect((BigDecimal("0.${"1".padLeft(pow(10, 0),"0")}")+BigDecimal("0.${"9".padLeft(pow(10, 0),"9")}")).toString(), BigDecimal.one.toString());
    expect((BigDecimal("0.${"1".padLeft(pow(10, 1),"0")}")+BigDecimal("0.${"9".padLeft(pow(10, 1),"9")}")).toString(), BigDecimal.one.toString());
    expect((BigDecimal("0.${"1".padLeft(pow(10, 2),"0")}")+BigDecimal("0.${"9".padLeft(pow(10, 2),"9")}")).toString(), BigDecimal.one.toString());
    expect((BigDecimal("0.${"1".padLeft(pow(10, 3),"0")}")+BigDecimal("0.${"9".padLeft(pow(10, 3),"9")}")).toString(), BigDecimal.one.toString());
    expect((BigDecimal("0.${"1".padLeft(pow(10, 4),"0")}")+BigDecimal("0.${"9".padLeft(pow(10, 4),"9")}")).toString(), BigDecimal.one.toString());

    print("Testing random");
    for(int i=0; i<10000; ++i) {
      print("\tEvaluating #${i.toString().padLeft(4)} ->");
      String strReal1 = generateNumber(decimal: false);
      String strDecimal1 = generateNumber(decimal: true);
      String number1 = "$strReal1.$strDecimal1";
      String strReal2 = generateNumber(decimal: false);
      String strDecimal2 = generateNumber(decimal: true);
      String number2 = "$strReal2.$strDecimal2";
      print("\t\t[${strReal1.length.toString().padLeft(5)}].[${strDecimal1.length.toString().padLeft(5)}]:${strReal1.padLeft(max(strReal1.length, strReal2.length)," ")}.$strDecimal1");
      print("\t\t[${strReal2.length.toString().padLeft(5)}].[${strDecimal2.length.toString().padLeft(5)}]:${strReal2.padLeft(max(strReal1.length, strReal2.length)," ")}.$strDecimal2");

      BigInt biReal1    = BigInt.parse(strReal1   );
      BigInt biDecimal1 = BigInt.parse(strDecimal1.padRight(max(strDecimal1.length, strDecimal2.length),"0"));
      BigInt biReal2    = BigInt.parse(strReal2   );
      BigInt biDecimal2 = BigInt.parse(strDecimal2.padRight(max(strDecimal1.length, strDecimal2.length),"0"));

      BigInt biDecimal3 = biDecimal1 + biDecimal2;

      String strDecimal3 = biDecimal3.toString();
      bool   carry       = max(strDecimal1.length, strDecimal2.length) != strDecimal3.length;
      BigInt biReal3     = biReal1    + biReal2 + (carry?BigInt.one : BigInt.zero);
      String strReal3    = biReal3.toString();
      if(carry) strDecimal3 = strDecimal3.substring(1);
      expect(BigDecimal(number1)+BigDecimal(number2), BigDecimal("$strReal3.$strDecimal3"));
    }
  });

  test("BigDecimal operator - test",()async{
    print("Testing Basic");
    expect((BigDecimal("1" )-BigDecimal("1" )).toString(), BigDecimal.zero .toString());
    expect((BigDecimal("2" )-BigDecimal("1" )).toString(), BigDecimal.one  .toString());
    expect((BigDecimal.zero -BigDecimal("1" )).toString(), BigDecimal("-1").toString());

    print("Testing Real");
    expect((BigDecimal("1".padRight(11   ,"0"))-BigDecimal.one).toString(), BigDecimal("9".padLeft (10   ,"9")).toString());
    expect((BigDecimal("1".padRight(101  ,"0"))-BigDecimal.one).toString(), BigDecimal("9".padLeft (100  ,"9")).toString());
    expect((BigDecimal("1".padRight(1001 ,"0"))-BigDecimal.one).toString(), BigDecimal("9".padLeft (1000 ,"9")).toString());
    expect((BigDecimal("1".padRight(10001,"0"))-BigDecimal.one).toString(), BigDecimal("9".padLeft (10000,"9")).toString());

    print("Testing Decimal");
    expect((BigDecimal.one-BigDecimal("0.${"1".padLeft(pow(10, 0),"0")}")).toString(), BigDecimal("0.${"9".padLeft(pow(10, 0),"9")}").toString());
    expect((BigDecimal.one-BigDecimal("0.${"1".padLeft(pow(10, 1),"0")}")).toString(), BigDecimal("0.${"9".padLeft(pow(10, 1),"9")}").toString());
    expect((BigDecimal.one-BigDecimal("0.${"1".padLeft(pow(10, 2),"0")}")).toString(), BigDecimal("0.${"9".padLeft(pow(10, 2),"9")}").toString());
    expect((BigDecimal.one-BigDecimal("0.${"1".padLeft(pow(10, 3),"0")}")).toString(), BigDecimal("0.${"9".padLeft(pow(10, 3),"9")}").toString());
    expect((BigDecimal.one-BigDecimal("0.${"1".padLeft(pow(10, 4),"0")}")).toString(), BigDecimal("0.${"9".padLeft(pow(10, 4),"9")}").toString());

    print("Testing random");
    for(int i=0; i<1000; ++i) {
      print("\tEvaluating #${i.toString().padLeft(4)} ->");
      String strReal1 = generateNumber(decimal: false);
      String strDecimal1 = generateNumber(decimal: true);
      String number1 = "$strReal1.$strDecimal1";
      String strReal2 = generateNumber(decimal: false);
      String strDecimal2 = generateNumber(decimal: true);
      String number2 = "$strReal2.$strDecimal2";
      print("\t\t[${strReal1.length.toString().padLeft(5)}].[${strDecimal1.length.toString().padLeft(5)}]:${strReal1.padLeft(max(strReal1.length, strReal2.length)," ")}.$strDecimal1");
      print("\t\t[${strReal2.length.toString().padLeft(5)}].[${strDecimal2.length.toString().padLeft(5)}]:${strReal2.padLeft(max(strReal1.length, strReal2.length)," ")}.$strDecimal2");

      BigInt biReal1    = BigInt.parse(strReal1   );
      BigInt biDecimal1 = BigInt.parse(strDecimal1.padRight(max(strDecimal1.length, strDecimal2.length),"0"));
      BigInt biReal2    = BigInt.parse(strReal2   );
      BigInt biDecimal2 = BigInt.parse(strDecimal2.padRight(max(strDecimal1.length, strDecimal2.length),"0"));

      int compare;
      if     (strReal1.length>strReal2.length) compare =  1;
      else if(strReal1.length<strReal2.length) compare = -1;
      else compare = strReal1.compareTo(strReal2);
      if(compare==0){
        String strDecimal3 = strDecimal1.padRight(max(strDecimal1.length, strDecimal2.length),"0");
        String strDecimal4 = strDecimal2.padRight(max(strDecimal1.length, strDecimal2.length),"0");
        compare = strDecimal3.compareTo(strDecimal4);
      }

      BigInt biDecimal3  = BigInt.zero;
      String strReal3    = "";
      String strDecimal3 = "";
      if(compare==1){
               biDecimal3 = biDecimal1 - biDecimal2;
        bool   borrow     = biDecimal3 < BigInt.zero;
        BigInt biReal3    = biReal1 - biReal2 - (borrow?BigInt.one : BigInt.zero);
               strReal3   = biReal3.toString();

        if(borrow) strDecimal3 = (biDecimal3 + BigInt.parse("1".padRight(max(strDecimal1.length, strDecimal2.length)+1,"0"))).toString();
        else strDecimal3 = biDecimal3.toString();
      }
      if(compare==-1){// a-b = -(b-a)
               biDecimal3 = biDecimal2 - biDecimal1;
        bool   borrow     = biDecimal3 < BigInt.zero;
        BigInt biReal3    = biReal2 - biReal1 - (borrow?BigInt.one : BigInt.zero);
               strReal3   = "-"+biReal3.toString();

        if(borrow) strDecimal3 = (biDecimal3 + BigInt.parse("1".padRight(max(strDecimal1.length, strDecimal2.length)+1,"0"))).toString();
        else strDecimal3 = biDecimal3.toString();
      }

      if(strDecimal3 != "0"){
        strDecimal3 = strDecimal3.padLeft(max(strDecimal1.length, strDecimal2.length),"0");
        while(strDecimal3.length>0){
          if(strDecimal3.substring(strDecimal3.length-1) == "0"){
            strDecimal3 = strDecimal3.substring(0, strDecimal3.length-1);
            continue;
          }
          break;
        }
      }

      expect(BigDecimal(number1)-BigDecimal(number2), BigDecimal("$strReal3.$strDecimal3"));
    }
  });

  test("BigDecimal operator * test",()async{
    print("Testing Basic");
    expect((BigDecimal("1" )*BigDecimal("1" )).toString(), BigDecimal("1" ).toString());
    expect((BigDecimal("-1")*BigDecimal("1" )).toString(), BigDecimal("-1").toString());
    expect((BigDecimal("-1")*BigDecimal("-1")).toString(), BigDecimal("1" ).toString());

    print("Testing Real");
    expect((BigDecimal("9".padLeft (10   ,"9"))*BigDecimal.one).toString(), BigDecimal("9".padLeft (10   ,"9")).toString());
    expect((BigDecimal("9".padLeft (100  ,"9"))*BigDecimal.one).toString(), BigDecimal("9".padLeft (100  ,"9")).toString());
    expect((BigDecimal("9".padLeft (1000 ,"9"))*BigDecimal.one).toString(), BigDecimal("9".padLeft (1000 ,"9")).toString());
    expect((BigDecimal("9".padLeft (10000,"9"))*BigDecimal.one).toString(), BigDecimal("9".padLeft (10000,"9")).toString());

    print("Testing Decimal");
    expect((BigDecimal("0.${"9".padLeft(pow(10, 0),"9")}")*BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 0),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 1),"9")}")*BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 1),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 2),"9")}")*BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 2),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 3),"9")}")*BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 3),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 4),"9")}")*BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 4),"9")}").toString());

    print("Testing random");
    for(int i=0; i<10000; ++i) {
      print("\tEvaluating #${i.toString().padLeft(4)} ->");
      String strReal1 = generateNumber(decimal: false);
      String strDecimal1 = generateNumber(decimal: true);
      String number1 = "$strReal1.$strDecimal1";
      String strReal2 = generateNumber(decimal: false);
      String strDecimal2 = generateNumber(decimal: true);
      String number2 = "$strReal2.$strDecimal2";
      print("\t\t[${strReal1.length.toString().padLeft(5)}].[${strDecimal1.length.toString().padLeft(5)}]:${strReal1.padLeft(max(strReal1.length, strReal2.length)," ")}.$strDecimal1");
      print("\t\t[${strReal2.length.toString().padLeft(5)}].[${strDecimal2.length.toString().padLeft(5)}]:${strReal2.padLeft(max(strReal1.length, strReal2.length)," ")}.$strDecimal2");

      BigInt biNum1 = BigInt.parse("$strReal1${strDecimal1.padRight(max(strDecimal1.length, strDecimal2.length),"0")}");
      BigInt biNum2 = BigInt.parse("$strReal2${strDecimal2.padRight(max(strDecimal1.length, strDecimal2.length),"0")}");
      BigInt biPow  = BigInt.parse("1".padRight(max(strDecimal1.length,strDecimal2.length)*2+1,"0"));

      BigInt biNum3 = biNum1 * biNum2;
      String strReal3 = (biNum3~/biPow).toString();
      String strDecimal3 = (biNum3%biPow).toString().padLeft(max(strDecimal1.length, strDecimal2.length)*2,"0");
      while(strDecimal3.length>0){
        if(strDecimal3.substring(strDecimal3.length-1) == "0"){
          strDecimal3 = strDecimal3.substring(0, strDecimal3.length-1);
          continue;
        }
        break;
      }
      expect(BigDecimal(number1)*BigDecimal(number2), BigDecimal("$strReal3.$strDecimal3"));
    }
    print("Test Passed");
  });

  test("BigDecimal operator / test",()async{
    print("Testing Basic");
    expect((BigDecimal("1" ).disablePrecisionLimit()/BigDecimal("0.1" )).toString(), BigDecimal("10").toString());
    expect((BigDecimal("1" ).disablePrecisionLimit()/BigDecimal("1"   )).toString(), BigDecimal("1" ).toString());
    expect((BigDecimal("-1").disablePrecisionLimit()/BigDecimal("1"   )).toString(), BigDecimal("-1").toString());
    expect((BigDecimal("-1").disablePrecisionLimit()/BigDecimal("-1"  )).toString(), BigDecimal("1" ).toString());

    print("Testing Real");
    expect((BigDecimal("9".padLeft (10   ,"9")).disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("9".padLeft (10   ,"9")).toString());
    expect((BigDecimal("9".padLeft (100  ,"9")).disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("9".padLeft (100  ,"9")).toString());
    expect((BigDecimal("9".padLeft (1000 ,"9")).disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("9".padLeft (1000 ,"9")).toString());
    expect((BigDecimal("9".padLeft (10000,"9")).disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("9".padLeft (10000,"9")).toString());

    print("Testing Decimal");
    expect((BigDecimal("0.${"9".padLeft(pow(10, 0),"9")}").disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 0),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 1),"9")}").disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 1),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 2),"9")}").disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 2),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 3),"9")}").disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 3),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 4),"9")}").disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 4),"9")}").toString());

    print("Testing random");
    for(int i=0; i<1000; ++i) {
      print("\tEvaluating #${i.toString().padLeft(4)} ->");
      String strReal1    = generateNumber(decimal: false, maxLength: 50);
      String strDecimal1 = generateNumber(decimal: true , maxLength: 50);
      String number1     = "$strReal1.$strDecimal1";
      String strReal2    = generateNumber(decimal: false, maxLength: 50);
      String strDecimal2 = generateNumber(decimal: true , maxLength: 50);
      String number2     = "$strReal2.$strDecimal2";
      print("\t\t[${strReal1.length.toString().padLeft(5)}].[${strDecimal1.length.toString().padLeft(5)}]:${strReal1.padLeft(max(strReal1.length, strReal2.length)," ")}.$strDecimal1");
      print("\t\t[${strReal2.length.toString().padLeft(5)}].[${strDecimal2.length.toString().padLeft(5)}]:${strReal2.padLeft(max(strReal1.length, strReal2.length)," ")}.$strDecimal2");

      StringBuilder sbDiv             = StringBuilder();
      int           nRealBitPrecision = strReal1.length + strDecimal2.length;
      int           pPrecision        = -nRealBitPrecision;
      int           char0             = "0".codeUnitAt(0);
      BigInt        biTen             = BigInt.from(10);
      String        strNum1           = "$strReal1$strDecimal1";
      BigInt        dividend          = BigInt.zero;
      BigInt        divisor           = BigInt.parse("$strReal2$strDecimal2");
      for(int i=0; i<strNum1.length || dividend!=BigInt.zero; ++i){
        if(pPrecision++>=1000) break;
        int num = i<strNum1.length ? (strNum1.codeUnitAt(i)-char0) : 0;
        dividend = dividend*biTen + BigInt.from(num);
        if(dividend<divisor){
          sbDiv.append(0);
          continue;
        }
        BigInt quotient  = dividend~/divisor;
        BigInt remainder = dividend%divisor;
        sbDiv.append(quotient.toString());
        dividend = remainder;
      }
      String strReal3    = sbDiv.substring(0                , nRealBitPrecision);
      String strDecimal3 = sbDiv.substring(nRealBitPrecision);
      while(strReal3.length>0){
        if(strReal3.substring(0,1) == "0"){
          strReal3 = strReal3.substring(1);
          continue;
        }
        break;
      }
      while(strDecimal3.length>0){
        if(strDecimal3.substring(strDecimal3.length-1) == "0"){
          strDecimal3 = strDecimal3.substring(0, strDecimal3.length-1);
          continue;
        }
        break;
      }
      expect(BigDecimal(number1)/BigDecimal(number2), BigDecimal("$strReal3.$strDecimal3"));
    }
    print("Test Passed");
  });

  test("BigDecimal operator / test 2",()async{
    print("Testing Basic");
    expect((BigDecimal("1" ).disablePrecisionLimit()/BigDecimal("0.1" )).toString(), BigDecimal("10").toString());
    expect((BigDecimal("1" ).disablePrecisionLimit()/BigDecimal("1"   )).toString(), BigDecimal("1" ).toString());
    expect((BigDecimal("-1").disablePrecisionLimit()/BigDecimal("1"   )).toString(), BigDecimal("-1").toString());
    expect((BigDecimal("-1").disablePrecisionLimit()/BigDecimal("-1"  )).toString(), BigDecimal("1" ).toString());

    print("Testing Real");
    expect((BigDecimal("9".padLeft (10   ,"9")).disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("9".padLeft (10   ,"9")).toString());
    expect((BigDecimal("9".padLeft (100  ,"9")).disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("9".padLeft (100  ,"9")).toString());
    expect((BigDecimal("9".padLeft (1000 ,"9")).disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("9".padLeft (1000 ,"9")).toString());
    expect((BigDecimal("9".padLeft (10000,"9")).disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("9".padLeft (10000,"9")).toString());

    print("Testing Decimal");
    expect((BigDecimal("0.${"9".padLeft(pow(10, 0),"9")}").disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 0),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 1),"9")}").disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 1),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 2),"9")}").disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 2),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 3),"9")}").disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 3),"9")}").toString());
    expect((BigDecimal("0.${"9".padLeft(pow(10, 4),"9")}").disablePrecisionLimit()/BigDecimal.one).toString(), BigDecimal("0.${"9".padLeft(pow(10, 4),"9")}").toString());

    print("Testing random");
    for(int i=0; i<10000; ++i) {
      print("\tEvaluating #${i.toString().padLeft(4)} ->");
      String strReal1    = generateNumber(decimal: false, maxLength: 50);
      String strDecimal1 = generateNumber(decimal: true, maxLength: 50);
      String number1     = "$strReal1.$strDecimal1";
      String strReal2    = generateNumber(decimal: false, maxLength: 50);
      String strDecimal2 = generateNumber(decimal: true, maxLength: 50);
      String number2     = "$strReal2.$strDecimal2";
      print("\t\t[${strReal1.length.toString().padLeft(5)}].[${strDecimal1.length.toString().padLeft(5)}]:${strReal1.padLeft(max(strReal1.length, strReal2.length)," ")}.$strDecimal1");
      print("\t\t[${strReal2.length.toString().padLeft(5)}].[${strDecimal2.length.toString().padLeft(5)}]:${strReal2.padLeft(max(strReal1.length, strReal2.length)," ")}.$strDecimal2");
      BigDecimal bd1 = BigDecimal(number1);
      BigDecimal bd2 = BigDecimal(number2);
      BigDecimal bd3 = bd1*bd2;
      expect(bd3.disablePrecisionLimit()/bd2, bd1);
    }
    print("Test Passed");
  },);
}
相关推荐
MavenTalk15 小时前
前端技术选型之uniapp
android·前端·flutter·ios·uni-app·前端开发
sunly_1 天前
Flutter:启动屏逻辑处理01:修改默认APP启动图标
flutter
sunly_1 天前
Flutter:启动屏逻辑处理02:启动页
android·javascript·flutter
Alex_z08971 天前
flutter gradle版本更新到8.9
flutter
那年星空1 天前
Flutter 设计模式全面解析:抽象工厂
flutter·设计模式·架构
林北芒大果2 天前
【Flutter】搭建Flutter开发环境,安卓开发
android·flutter
SunshineBrother2 天前
Flutter求职、面试20+面试官总结:Dart篇
android·前端·flutter
李新_2 天前
一文聊聊Flutter多业务混合工程实践
android·flutter
sunly_2 天前
Flutter:flutter_screenutil屏幕适配
前端·javascript·flutter
sunly_3 天前
Flutter:AnimatedPadding动态修改padding
android·flutter