提问人:Lucas Meadows 提问时间:2/10/2015 更新时间:10/7/2023 访问量:338592
如何在小数点后将 Dart 中的双精度四舍五入到给定的精度?
How do you round a double in Dart to a given degree of precision AFTER the decimal point?
问:
给定一个双精度,我想在小数点后将其四舍五入到给定数量的精度点,类似于 PHP 的 round() 函数。
我在 Dart 文档中可以找到的最接近的是 double.toStringAsPrecision(),但这并不是我所需要的,因为它包括总精度点中小数点之前的数字。
例如,使用 toStringAsPrecision(3):
0.123456789 rounds to 0.123
9.123456789 rounds to 9.12
98.123456789 rounds to 98.1
987.123456789 rounds to 987
9876.123456789 rounds to 9.88e+3
随着数字大小的增加,我在小数点后的位置相应地失去了精度。
答:
void main() {
int decimals = 2;
int fac = pow(10, decimals);
double d = 1.234567889;
d = (d * fac).round() / fac;
print("d: $d");
}
指纹: 1.23
评论
请参阅 num.toStringAsFixed()
的文档。
toStringAsFixed(int fractionDigits) → String
此数字的小数点字符串表示形式。
在计算字符串表示形式之前将其转换为双精度值。
如果 this 的绝对值大于或等于,则此方法返回由 计算的指数表示。
10^21
this.toStringAsExponential()
例子:
1000000000000000000000.toStringAsExponential(3); // 1.000e+21
否则,结果是最接近的字符串表示形式,小数点后的数字正好。如果等于,则省略小数点。
fractionDigits
fractionDigits
0
该参数必须是满足以下条件的整数: 。
fractionDigits
0 <= fractionDigits <= 20
例子:
1.toStringAsFixed(3); // 1.000 (4321.12345678).toStringAsFixed(3); // 4321.123 (4321.12345678).toStringAsFixed(5); // 4321.12346 123456789012345678901.toStringAsFixed(3); // 123456789012345683968.000 1000000000000000000000.toStringAsFixed(3); // 1e+21 5.25.toStringAsFixed(0); // 5
评论
5.550.toStringAsFixed(1)
int
double
num.parse(50.123.toStringAsFixed(0)) is int
.toDouble()
double
toStringAsFixed(1)
12.000
12
12.011
12.011
num.toStringAsFixed()
轮。这个方法将你的 num (n) 变成一个字符串,其中包含你想要的小数位数 (2),然后在一行代码中将其解析回你的 num:
n = num.parse(n.toStringAsFixed(2));
评论
extension NumberRounding on num { num toPrecision(int precision) { return num.parse((this).toStringAsFixed(precision)); } }
双精度
,因为这是一件愚蠢的事情。您想要的十进制值很可能不会完全表示为 .toStringAsFixed
double
double
double
上述解决方案不能适当地对数字进行四舍五入。我使用:
double dp(double val, int places){
num mod = pow(10.0, places);
return ((val * mod).round().toDouble() / mod);
}
评论
dp(5.550, 1)
5.6
5.5
var price = 99.012334554;
price = price.toStringAsFixed(2);
print(price); // 99.01
那是飞镖的参考。 编号: https://api.dartlang.org/stable/2.3.0/dart-core/num/toStringAsFixed.html
评论
我使用这种方法将数字四舍五入到小数点后的特定数字
前任:toStringAsFixed()
double num = 22.48132906
当我把它四舍五入到两个数字时,就像这样:
print(num.toStringAsFixed(2)) ;
它打印了22.48
当我四舍五入到一个数字时,它打印出来了22.5
评论
使用 Dart 扩展方法@andyw修改后的答案:
extension Precision on double {
double toPrecision(int fractionDigits) {
double mod = pow(10, fractionDigits.toDouble());
return ((this * mod).round().toDouble() / mod);
}
}
用法:
var latitude = 1.123456;
var latitudeWithFixedPrecision = latitude.toPrecision(3); // Outputs: 1.123
这效果很好
var price=99.012334554
price = price.roundTodouble();
print(price); // 99.01
要在 Dart 中将 double 四舍五入到小数点后给定的精度,您可以使用 dart 方法中的内置解决方案,但您必须将其转换回 doubletoStringAsFixed()
void main() {
double step1 = 1/3;
print(step1); // 0.3333333333333333
String step2 = step1.toStringAsFixed(2);
print(step2); // 0.33
double step3 = double.parse(step2);
print(step3); // 0.33
}
评论
double
上述解决方案并不适用于所有情况。对我的问题有效的是这个解决方案,它将四舍五入您的数字(0.5 到 1 或 0.49 到 0)并使其没有任何小数:
输入: 12.67
double myDouble = 12.67;
var myRoundedNumber; // Note the 'var' datatype
// Here I used 1 decimal. You can use another value in toStringAsFixed(x)
myRoundedNumber = double.parse((myDouble).toStringAsFixed(1));
myRoundedNumber = myRoundedNumber.round();
print(myRoundedNumber);
输出: 13
您可以使用 in 来显示小数点后的限制数字。 返回小数点字符串表示形式。 接受一个名为 该参数是我们要显示的小数点后的数字。以下是如何使用它。toStringAsFixed
toStringAsFixed
toStringAsFixed
fraction Digits
double pi = 3.1415926;
const val = pi.toStringAsFixed(2); // 3.14
直接方式:
double d = 2.3456789;
String inString = d.toStringAsFixed(2); // '2.35'
double inDouble = double.parse(inString); // 2.35
使用扩展:
extension Ex on double {
double toPrecision(int n) => double.parse(toStringAsFixed(n));
}
用法:
void main() {
double d = 2.3456789;
double d1 = d.toPrecision(1); // 2.3
double d2 = d.toPrecision(2); // 2.35
double d3 = d.toPrecision(3); // 2.345
}
评论
this.parse(toStringAsFixed(n));
)
double.parse
static
double
double
2.30
如果当生成的小数都是零时,您不需要任何小数,那么这样就可以了:
String fixedDecimals(double d, int decimals, {bool removeZeroDecimals = true}){
double mod = pow(10.0, decimals);
double result = ((d * mod).round().toDouble() / mod);
if( removeZeroDecimals && result - (result.truncate()) == 0.0 ) decimals = 0;
return result.toStringAsFixed(decimals);
}
这将简单地输出,而不是输入是并且您想要 2 位小数。9
9.00
9.004
评论
How do you round a double in Dart to a given degree of precision ...
double value = 2.8032739273;
String formattedValue = value.toStringAsFixed(3);
评论
toStringAsFixed
只需将此扩展写在双
extension Round on double {
double roundToPrecision(int n) {
int fac = pow(10, n).toInt();
return (this * fac).round() / fac;
}
}
评论
int fac
pow()
num
int
toInt()
我认为公认的答案不是完美的解决方案,因为它转换为 .string
如果您不想从 GetX 包转换和转换回使用。string
double
double.toPrecision(decimalNumber)
如果你不想只为此使用 GetX(我强烈推荐 GetX,它会用 flutter 改变你的生活),你可以复制并粘贴它。
当您想要使用扩展名时,请重新导入文件。
import 'dart:math';
extension Precision on double {
double toPrecision(int fractionDigits) {
var mod = pow(10, fractionDigits.toDouble()).toDouble();
return ((this * mod).round().toDouble() / mod);
}
}
ABANDONED !!!
-> 请参阅@luke77的代码 - 它用更精简的代码正确地解决了这个问题。
这个DART四舍五入问题已经存在了很长时间(@LucasMeadows),因为很明显,直到现在还没有得到充分解决(正如@DeepShah的观察所表明的那样)。
众所周知的舍入规则(未解决的问题):
" 以数字 5 结尾的数字四舍五入:如果结果为偶数,则向上舍入;如果结果为奇数,则向下舍入。 "
所以这里是DART代码解决方案:
double roundAccurately(double numToRound, int decimals) {
// Step 1 - Prime IMPORTANT Function Parameters ...
int iCutIndex = 0;
String sDeciClipdNTR = "";
num nMod = pow(10.0, decimals);
String sNTR = numToRound.toString();
int iLastDigitNTR = 0, i2ndLastDigitNTR = 0;
debugPrint("Round => $numToRound to $decimals Decimal ${(decimals == 1) ? "Place" : "Places"} !!"); // Deactivate this 'print()' line in production code !!
// Step 2 - Calculate Decimal Cut Index (i.e. string cut length) ...
int iDeciPlaces = (decimals + 2);
if (sNTR.contains('.')) {
iCutIndex = sNTR.indexOf('.') + iDeciPlaces;
} else {
sNTR = sNTR + '.';
iCutIndex = sNTR.indexOf('.') + iDeciPlaces;
}
// Step 3 - Cut input double to length of requested Decimal Places ...
if (iCutIndex > sNTR.length) { // Check that decimal cutting is possible ...
sNTR = sNTR + ("0" * iDeciPlaces); // ... and fix (lengthen) the input double if it is too short.
sDeciClipdNTR = sNTR.substring(0, iCutIndex); // ... then cut string at indicated 'iCutIndex' !!
} else {
sDeciClipdNTR = sNTR.substring(0, iCutIndex); // Cut string at indicated 'iCutIndex' !!
}
// Step 4 - Extract the Last and 2nd Last digits of the cut input double.
int iLenSDCNTR = sDeciClipdNTR.length;
iLastDigitNTR = int.parse(sDeciClipdNTR.substring(iLenSDCNTR - 1)); // Extract the last digit !!
(decimals == 0)
? i2ndLastDigitNTR = int.parse(sDeciClipdNTR.substring(iLenSDCNTR - 3, iLenSDCNTR - 2))
: i2ndLastDigitNTR = int.parse(sDeciClipdNTR.substring(iLenSDCNTR - 2, iLenSDCNTR - 1));
// Step 5 - Execute the FINAL (Accurate) Rounding Process on the cut input double.
double dAccuRound = 0;
if (iLastDigitNTR == 5 && ((i2ndLastDigitNTR + 1) % 2 != 0)) {
dAccuRound = double.parse(sDeciClipdNTR.substring(0, iLenSDCNTR - 1));
} else {
if (iLastDigitNTR < 5) {
dAccuRound = double.parse(sDeciClipdNTR.substring(0, iLenSDCNTR - 1));
} else {
if (decimals == 0) {
sDeciClipdNTR = sNTR.substring(0, iCutIndex - 2);
dAccuRound = double.parse(sDeciClipdNTR) + 1; // Finally - Round UP !!
} else {
double dModUnit = 1 / nMod;
sDeciClipdNTR = sNTR.substring(0, iCutIndex - 1);
dAccuRound = double.parse(sDeciClipdNTR) + dModUnit; // Finally - Round UP !!
}
}
}
// Step 6 - Run final QUALITY CHECK !!
double dResFin = double.parse(dAccuRound.toStringAsFixed(decimals));
// Step 7 - Return result to function call ...
debugPrint("Result (AccuRound) => $dResFin !!"); // Deactivate this 'print()' line in production code !!
return dResFin;
}
这是一种完全手动的方法(可能有点矫枉过正),但它有效。请测试它(直到筋疲力尽),如果我错过了标记,请告诉我。
ABANDONED !!!
-> 请参阅@luke47的代码 - 它用更精简的代码正确地解决了这个问题。
评论
roundAccurately(73.4750, 2)
73.48
Decimal.parse(this.toString()).round(scale: places).toDouble()
您可以创建一个可重用的函数,该函数接受要格式化的 numberOfDecimal 并利用 toStringAsFixed() 方法格式化数字并将其转换回双精度。
仅供参考,toStringAsFixed 方法不会舍入以 5 结尾的数字(例如:toStringAsFixed 将 2.275 四舍五入到 2.27 而不是 2.28)。这是 dart toStringAsFixed 方法的默认行为(类似于 Javascript toFixed)
作为解决方法,我们可以在最后一个十进制数之后将现有数字加 1(例如:将 0.0001 添加到 2.275 变成 2.2751,2.2751 将正确四舍五入为 2.28)
double roundOffToXDecimal(double number, {int numberOfDecimal = 2}) {
// To prevent number that ends with 5 not round up correctly in Dart (eg: 2.275 round off to 2.27 instead of 2.28)
String numbersAfterDecimal = number.toString().split('.')[1];
if (numbersAfterDecimal != '0') {
int existingNumberOfDecimal = numbersAfterDecimal.length;
double incrementValue = 1 / (10 * pow(10, existingNumberOfDecimal));
if (number < 0) {
number -= incrementValue;
} else {
number += incrementValue;
}
}
return double.parse(number.toStringAsFixed(numberOfDecimal));
}
// Example of usage:
var price = roundOffToXDecimal(2.275, numberOfDecimal: 2)
print(price); // 2.28
评论
two thumbs up
]
.toStringAsFixed()
确实将以 5 结尾的数字四舍五入; 是 , 是 , 是 和 是 。正如此答案链接到的线程所解释的那样,通常不会发生这种情况的原因是 s 在表示十进制数时本质上是不精确的。例如,2.275 实际上是 2.274999999999999991182158029987476766109466552734375。0.5.toStringAsFixed(0)
'1'
0.25.toStringAsFixed(1)
'0.3'
0.125.toStringAsFixed(2)
'0.13'
double
double
toStringAsFixed()
when rounding a number ending with a 5 round up if the result is an even number, but don't round if result is an odd number
double
如果使用动态类型的数据。你可以使用它。
typeDecimal(data) => num.parse(data.toString()).toStringAsFixed(2);
您可以简单地将该值乘以 100,然后四舍五入,然后再除以 100。
(number * 100).round() / 100.0;
此外,如果您想在文本中舍入双精度值。
文本('${carpetprice.toStringAsFixed(3)}',),
如果要获得结果,将 IEEE-754 二进制浮点数四舍五入到特定数量的十进制数字本身就存在问题。double
double
就像像 1/3 这样的分数不能用有限数量的十进制数字精确表示一样,许多(嗯,无限多)十进制数不能用有限数量的二进制数字表示。例如,十进制数 0.1 不能用二进制精确表示。虽然您可以尝试将 0.09999 四舍五入为 0.1,但它实际上会“四舍五入”为 0.10000000000000000055511151231257827021181583404541015625。大多数其他声称具有十进制精度的舍入 s 的答案实际上返回最接近的可表示对象。当您通过将这些值转换为 s 来向用户显示这些值时,您可能会看到比预期更多的数字。double
double
double
String
你可以做的是,当你最终向用户显示字符串表示时,它看起来像一个漂亮的四舍五入数字,这就是double.toStringAsFixed()
的作用。这也是为什么当你打印 0.100000000...时,你可能会看到实现是否试图漂亮地打印用户友好的值。但是,不要被愚弄:该值实际上永远不会完全是 0.1,如果您使用如此不精确的值进行重复算术运算,则可能会累积误差(例如:0.1 + 0.2)。0.1
double
请注意,以上所有内容都是二进制浮点数工作方式的基础,并非特定于 Dart。另请参阅:
- 浮点数学坏了吗?
- 如果你不明白上面的解释,Tom Scott 还制作了一个很棒的视频来解释浮点是如何工作的。
底线:如果您关心十进制精度,请不要使用二进制浮点类型。如果您要处理金钱,这一点尤其重要。
您应该改用:
- 整数。例如,如果您正在处理货币,则使用 ,而不是使用 。然后,您的计算将始终是准确的,并且只有在向用户显示它们时才能转换为所需的单位(同样,在读取用户的输入时也可以以相反的方向进行转换)。
double dollars = 1.23;
int cents = 123;
- 一种类型,旨在以任意精度表示十进制数。例如,
package:decimal
提供了一个类型。对于这种类型,其他一些答案(例如乘以 100、四舍五入,然后除以 100)将是合适的。(但实际上你应该直接使用Decimal.round
。Decimal
评论
Decimal.parse(this.toString()).round(scale: places).toDouble()
toDouble()
package:decimal
double
double
我在双倍上做了这个扩展
import 'dart:math';
extension DoubleExtension on double {
/// rounds the double to a specific decimal place
double roundedPrecision(int places) {
double mod = pow(10.0, places) as double;
return ((this * mod).round().toDouble() / mod);
}
/// good for string output because it can remove trailing zeros
/// and sometimes periods. Or optionally display the exact number of trailing
/// zeros
String roundedPrecisionToString(
int places, {
bool trailingZeros = false,
}) {
double mod = pow(10.0, places) as double;
double round = ((this * mod).round().toDouble() / mod);
String doubleToString =
trailingZeros ? round.toStringAsFixed(places) : round.toString();
if (!trailingZeros) {
RegExp trailingZeros = RegExp(r'^[0-9]+.0+$');
if (trailingZeros.hasMatch(doubleToString)) {
doubleToString = doubleToString.split('.')[0];
}
}
return doubleToString;
}
String toStringNoTrailingZeros() {
String doubleToString = toString();
RegExp trailingZeros = RegExp(r'^[0-9]+.0+$');
if (trailingZeros.hasMatch(doubleToString)) {
doubleToString = doubleToString.split('.')[0];
}
return doubleToString;
}
}
以下是通过测试。
import 'package:flutter_test/flutter_test.dart';
import 'package:project_name/utils/double_extension.dart';
void main() {
group("rounded precision", () {
test("rounding to 0 place results in an int", () {
double num = 5.1234;
double num2 = 5.8234;
expect(num.roundedPrecision(0), 5);
expect(num2.roundedPrecision(0), 6);
});
test("rounding to 1 place rounds correctly to 1 place", () {
double num = 5.12;
double num2 = 5.15;
expect(num.roundedPrecision(1), 5.1);
expect(num2.roundedPrecision(1), 5.2);
});
test(
"rounding a number to a precision that is more accurate than the origional",
() {
double num = 5;
expect(num.roundedPrecision(5), 5);
});
});
group("rounded precision returns the correct string", () {
test("rounding to 0 place results in an int", () {
double num = 5.1234;
double num2 = 5.8234;
expect(num.roundedPrecisionToString(0), "5");
expect(num2.roundedPrecisionToString(0), "6");
});
test("rounding to 1 place rounds correct", () {
double num = 5.12;
double num2 = 5.15;
expect(num.roundedPrecisionToString(1), "5.1");
expect(num2.roundedPrecisionToString(1), "5.2");
});
test("rounding to 2 places rounds correct", () {
double num = 5.123;
double num2 = 5.156;
expect(num.roundedPrecisionToString(2), "5.12");
expect(num2.roundedPrecisionToString(2), "5.16");
});
test("cut off all trailing zeros (and periods)", () {
double num = 5;
double num2 = 5.03000;
expect(num.roundedPrecisionToString(5), "5");
expect(num2.roundedPrecisionToString(5), "5.03");
});
});
}
我像这样转换我=> `
num.tryParse("23.123456789")!.toDouble().roundToDouble()
`
你可以调用这个函数来获得 dark(flutter) 的精度。 double eval -> 要转换的 double int i ->要返回的小数点数。
double doubleToPrecision(double eval, int i) {
double step1 = eval;//1/3
print(step1); // 0.3333333333333333
String step2 = step1.toStringAsFixed(2);
print(step2); // 0.33
double step3 = double.parse(step2);
print(step3); // 0.33
eval = step3;
return eval; }
如果需要,请使用特殊的舍入。您可以尝试此函数(舍入)。
void main(List<String> arguments) {
list.map((e) {
log('list1');
rounding(e, 0.05);
rounding(e, 0.1);
rounding(e, 0.2);
rounding(e, 0.25);
rounding(e, 0.5);
rounding(e, 1);
rounding(e, 10);
}).toList();
list2.map((e) {
log('list2');
rounding(e, 0.05);
rounding(e, 0.1);
rounding(e, 0.2);
rounding(e, 0.25);
rounding(e, 0.5);
rounding(e, 1);
rounding(e, 10);
}).toList();
}
const list = [1.11, 1.22, 1.33, 1.44, 1.55, 1.66, 1.77, 1.88, 1.99];
const list2 = [2.19, 3.28, 4.37, 5.46, 6.55, 7.64, 8.73, 9.82, 10.91];
void rounding(double price, double count) {
log('-----------------------');
log('price: $price, count: $count');
double _priceRemainder = price % count;
double _someDiff = count / _priceRemainder;
log('_price: ${_priceRemainder.toStringAsFixed(2)}');
log('_pricePlus: ${_someDiff.toStringAsFixed(2)}');
if (_someDiff.toStringAsFixed(2) == '1.00') {
log('_someDiff = 1');
} else if (_someDiff > 1 && _someDiff <= 2 ||
_someDiff.toStringAsFixed(2) == '2.00') {
log('_someDiff > 1 && _someDiff <= 2 || _someDiff.toStringAsFixed(2) == 2.00');
log('ceilToDouble: $price: ${(price + (count - _priceRemainder)).toStringAsFixed(2)}');
log('floorToDouble: $price: ${(price - _priceRemainder).toStringAsFixed(2)}');
log('roundToDouble: $price: ${(price + (count - _priceRemainder)).toStringAsFixed(2)}');
} else if (_someDiff > 2) {
log('_someDiff > 2');
log('ceilToDouble: $price: ${(price + (count - _priceRemainder)).toStringAsFixed(2)}');
log('floorToDouble: $price: ${(price - _priceRemainder).toStringAsFixed(2)}');
log('roundToDouble: $price: ${(price - _priceRemainder).toStringAsFixed(2)}');
}
log('-----------------------');
}
调试控制台:
[log] price: 10.91, count: 0.05
[log] _price: 0.01
[log] _pricePlus: 5.00
[log] _someDiff > 2
[log] ceilToDouble: 10.91: 10.95
[log] floorToDouble: 10.91: 10.90
[log] roundToDouble: 10.91: 10.90
2
[log] -----------------------
[log] price: 10.91, count: 0.1
[log] _price: 0.01
[log] _pricePlus: 10.00
[log] _someDiff > 2
[log] ceilToDouble: 10.91: 11.00
[log] floorToDouble: 10.91: 10.90
[log] roundToDouble: 10.91: 10.90
2
[log] -----------------------
[log] price: 10.91, count: 0.2
[log] _price: 0.11
[log] _pricePlus: 1.82
[log] _someDiff > 1 && _someDiff <= 2 || _someDiff.toStringAsFixed(2) == 2.00
[log] ceilToDouble: 10.91: 11.00
[log] floorToDouble: 10.91: 10.80
[log] roundToDouble: 10.91: 11.00
2
[log] -----------------------
[log] price: 10.91, count: 0.25
[log] _price: 0.16
[log] _pricePlus: 1.56
[log] _someDiff > 1 && _someDiff <= 2 || _someDiff.toStringAsFixed(2) == 2.00
[log] ceilToDouble: 10.91: 11.00
[log] floorToDouble: 10.91: 10.75
[log] roundToDouble: 10.91: 11.00
2
[log] -----------------------
[log] price: 10.91, count: 0.5
[log] _price: 0.41
[log] _pricePlus: 1.22
[log] _someDiff > 1 && _someDiff <= 2 || _someDiff.toStringAsFixed(2) == 2.00
[log] ceilToDouble: 10.91: 11.00
[log] floorToDouble: 10.91: 10.50
[log] roundToDouble: 10.91: 11.00
2
[log] -----------------------
[log] price: 10.91, count: 1.0
[log] _price: 0.91
[log] _pricePlus: 1.10
[log] _someDiff > 1 && _someDiff <= 2 || _someDiff.toStringAsFixed(2) == 2.00
[log] ceilToDouble: 10.91: 11.00
[log] floorToDouble: 10.91: 10.00
[log] roundToDouble: 10.91: 11.00
2
[log] -----------------------
[log] price: 10.91, count: 10.0
[log] _price: 0.91
[log] _pricePlus: 10.99
[log] _someDiff > 2
[log] ceilToDouble: 10.91: 20.00
[log] floorToDouble: 10.91: 10.00
[log] roundToDouble: 10.91: 10.00
如果您需要适当的四舍五入(当第一位数字为 5 时向上),并且想要尾随 0,您可以使用以下方法:
import 'dart:math';
String customRound(double val, int places) {
num mod = pow(10.0, places);
return ((val * mod).round().toDouble() / mod).toStringAsFixed(places);
}
customRound(2.345) // -> 2.35
customRound(2.500) // -> 2.50
从没想过这在 Dart 中如此复杂,但这是我的解决方案:
double truncateDouble(double val, int decimals) {
String valString = val.toString();
int dotIndex = valString.indexOf('.');
// not enough decimals
int totalDecimals = valString.length - dotIndex - 1;
if (totalDecimals < decimals) {
decimals = totalDecimals;
}
valString = valString.substring(0, dotIndex + decimals + 1);
return double.parse(valString);
}
var val = truncateDouble(44.999, 2);
评论
double
String
truncateDouble(73.4750, 2)
73.47
73.48
double roundOffToXDecimal(num number, {int precision = 2}) {
var precisionWithPow10 = pow(10, precision);
return (number * precisionWithPow10).round() / precisionWithPow10;
评论