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

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]<
  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值