Dart(flutter) 小数(double)运算 出现多位小数或精度问题 以及 数值操作

1,263 阅读2分钟

问题

Dart中的 double 与 js 中的 小数运算 一样,会出现 精度问题, 如以下情况:

var a = 1.0; 
var b = 1; 
var c = 1.1; 
a - b = 1.00;
c - b = 0.10000000000000000009;
0.2 + 0.1 = 0.30000000000000004;

原因

Dart 使用了和js一样的 IEEE 754 双精度标准进行存储。

解决方案

像js一样 将 小数转化为 整数 后,计算后再 转回小数

int aInt = (a*100).floor();
int bInt = (b*100).floor();
int cInt = (c*100).floor();
(aInt - bInt)/100   =   1
(cInt - bInt)/100   =   0.1

使用 第三方库decimal

import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  test('decimal测试', () {
    var d = Decimal.parse;
    var tmp = d('1') + d((d('10') / d('100')).toDouble().toString());
    debugPrint('${d('200') * tmp}');
    debugPrint((200 * (1 + (10.0 / 100.0))).toString());
  });
}

输出结果

220
220.00000000000003

d('10') / d('100')得到的数据类型是Rational, Rational无法直接用于计算,直接toString()得到的结果是10/100, 因此得先toDouble()得到0.1,再toString()得到对应字符

扩展: 数值操作

舍弃小数部分(取整)

double price = 100 / 3;

//舍弃当前变量的小数部分,结果为 33。返回值为 int 类型。
price.truncate();
//舍弃当前变量的小数部分,浮点数形式表示,结果为 33.0。返回值为 double。
price.truncateToDouble();
//舍弃当前变量的小数部分,结果为 33。返回值为 int 类型。
price.toInt();
//小数部分向上进位,结果为 34。返回值为 int 类型。
price.ceil();
//小数部分向上进位,结果为 34.0。返回值为 double。
price.ceilToDouble();
//当前变量四舍五入后取整,结果为 33。返回值为 int 类型。
price.round();
//当前变量四舍五入后取整,结果为 33.0。返回值为 double 类型。
price.roundToDouble();

保留小数点后 n 位

double price = 100 / 3;
//保留小数点后2位数,并返回字符串:33.33。
price.toStringAsFixed(2);
//保留小数点后5位数,并返回一个字符串 33.33333。
price.toStringAsFixed(5);