问题
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);