如何在小数点后将 Dart 中的双精度四舍五入到给定的精度?

How do you round a double in Dart to a given degree of precision AFTER the decimal point?

提问人:Lucas Meadows 提问时间:2/10/2015 更新时间:10/7/2023 访问量:338592

问:

给定一个双精度,我想在小数点后将其四舍五入到给定数量的精度点,类似于 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

随着数字大小的增加,我在小数点后的位置相应地失去了精度。

DART 双精度

评论


答:

31赞 Robert 2/10/2015 #1
void main() {
  int decimals = 2;
  int fac = pow(10, decimals);
  double d = 1.234567889;
  d = (d * fac).round() / fac;
  print("d: $d");
}

指纹: 1.23

评论

3赞 lrn 2/11/2015
这是目前最好的方法。四舍五入到像 0.01 这样的精度,这本身不是双精度,这并非易事。结果甚至可能根本无法表示为双精度。我强烈建议将整数用于任何十进制精度很重要的东西(比如,金钱)。
1赞 Greg Lowe 2/11/2015
另外值得指出的是,如果编译为 js,那么 Dart 整数也会开始失去精度,你需要使用如下包: pub.dartlang.org/packages/bignum
0赞 gi097 8/20/2018
这种方法感觉是目前最好、最优雅的方法。
449赞 Greg Lowe 2/10/2015 #2

请参阅 num.toStringAsFixed() 的文档。

toStringAsFixed(int fractionDigits) → String

此数字的小数点字符串表示形式。

在计算字符串表示形式之前将其转换为双精度值。

  • 如果 this 的绝对值大于或等于,则此方法返回由 计算的指数表示。10^21this.toStringAsExponential()

    例子:

    1000000000000000000000.toStringAsExponential(3); // 1.000e+21
    
  • 否则,结果是最接近的字符串表示形式,小数点后的数字正好。如果等于,则省略小数点。fractionDigitsfractionDigits0

    该参数必须是满足以下条件的整数: 。fractionDigits0 <= 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赞 brendan 1/15/2020
我认为 toStringAsFixed() 是要使用的舍入方法,因为它不一致。例如,尝试5.550.toStringAsFixed(1)
0赞 abulka 8/22/2020
四舍五入到 0 位时也要注意,因为表达式在这种情况下返回 an 而不是 a,例如 - 这可以通过添加到它的末尾来修复。intdoublenum.parse(50.123.toStringAsFixed(0)) is int.toDouble()
0赞 jamesdlin 2/28/2022
@brendan 鉴于尝试存储 5.55 的 a 实际上是 5.54999999999999998...然后返回正确答案 (5.5)。doubletoStringAsFixed(1)
1赞 Rob Caraway 12/8/2022
有没有好办法做到这一点,但如果尾部小数都是零,也让它显示零小数?例如:将显示为,但仍会显示为?12.0001212.01112.011
132赞 Yngvar Natland 8/25/2015 #3

num.toStringAsFixed()轮。这个方法将你的 num (n) 变成一个字符串,其中包含你想要的小数位数 (2),然后在一行代码中将其解析回你的 num:

n = num.parse(n.toStringAsFixed(2));

评论

28赞 ThinkDigital 10/12/2018
这是最快的方法。但愚蠢的是,飞镖没有直接的方法来做到这一点
3赞 Vit Veres 4/6/2020
扩展方法:extension NumberRounding on num { num toPrecision(int precision) { return num.parse((this).toStringAsFixed(precision)); } }
0赞 jamesdlin 3/1/2022
@ThinkDigital Dart 确实有一个直接的方法:.它没有直接的方法将 a 四舍五入到指定数量的十进制数字并将结果保留为双精度,因为这是一件愚蠢的事情。您想要的十进制值很可能不会完全表示为 .toStringAsFixeddoubledouble
0赞 jamesdlin 3/1/2022
我认为这个答案应该澄清,这段代码实际上所做的是返回最接近四舍五入的值。double
2赞 Stefan Rein 10/13/2022
进行了一些快速测量。toString 和解析速度大约比 POW 的数学解决方案慢 50 倍,迭代次数为 1000 万次。100 万次迭代速度慢 25 倍,100 000 次迭代速度慢 10 倍。万一有人想知道,像我一样。
70赞 andyw 11/27/2018 #4

上述解决方案不能适当地对数字进行四舍五入。我使用:

double dp(double val, int places){ 
   num mod = pow(10.0, places); 
   return ((val * mod).round().toDouble() / mod); 
}

评论

0赞 abulka 8/22/2020
确认后,这正确地四舍五入为 - 与最流行的答案不同,正如@brendan指出的那样,它给出了一个略微不正确的答案。dp(5.550, 1)5.65.5
3赞 Deep Shah 9/15/2020
不适用于 dp(73.4750, 2) 它返回 73.47 而不是 73.48 calculatorsoup.com/calculators/math/... 查看此链接
0赞 SilSur 3/28/2021
@DeepShah我相信这个答案 -> [ stackoverflow.com/a/66840734/3002719 ] 解决了您对您在上面确定的“数字 5 四舍五入规则”问题的担忧。
0赞 jamesdlin 8/30/2021
这本身就存在问题,因为将 IEEE-754 浮点数(二进制)四舍五入到十进制精度是无意义的;许多小数小数不能用二进制表示。另请参阅浮点数学是否损坏?
0赞 Nazmus Saadat 1/3/2022
你能把 4436.605 转换为 4436.61 (有 2 个位置)
37赞 Rizwan Ansar 5/4/2019 #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

评论

0赞 jamesdlin 3/1/2022
这个答案并没有给格雷格·洛(Greg Lowe)更早的答案增加任何内容。
27赞 Sana'a Al-ahdal 12/25/2019 #6

我使用这种方法将数字四舍五入到小数点后的特定数字 前任:toStringAsFixed()

double num = 22.48132906

当我把它四舍五入到两个数字时,就像这样:

print(num.toStringAsFixed(2)) ;

它打印了22.48

当我四舍五入到一个数字时,它打印出来了22.5

评论

1赞 jamesdlin 3/1/2022
这个答案并没有给格雷格·洛(Greg Lowe)更早的答案增加任何内容。
22赞 kubastick 12/30/2019 #7

使用 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
-5赞 Andrew Kawalya 5/8/2020 #8

这效果很好

var price=99.012334554
price = price.roundTodouble();
print(price); // 99.01
14赞 sultanmyrza 5/31/2020 #9

要在 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
}

评论

2赞 jamesdlin 3/1/2022
这个答案并没有给 Yngvar Natland 更早的答案增加任何内容。另外,我认为这个答案应该澄清,这段代码实际上所做的是返回最接近舍入值的值。double
5赞 Runsis 6/16/2020 #10

上述解决方案并不适用于所有情况。对我的问题有效的是这个解决方案,它将四舍五入您的数字(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

此链接也有其他解决方案

9赞 Hadi Mir 8/4/2020 #11

您可以使用 in 来显示小数点后的限制数字。 返回小数点字符串表示形式。 接受一个名为 该参数是我们要显示的小数点后的数字。以下是如何使用它。toStringAsFixedtoStringAsFixedtoStringAsFixedfraction Digits

double pi = 3.1415926;
const val = pi.toStringAsFixed(2); // 3.14
104赞 CopsOnRoad 9/28/2020 #12

直接方式:

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
}

评论

0赞 kyu 6/24/2021
我不明白这是怎么回事。为什么 double.parse 返回 double,因为我们没有传递对它的引用?(我在想类似的东西this.parse(toStringAsFixed(n));)
1赞 jamesdlin 3/1/2022
@kyu 是类型上的方法。double.parsestaticdouble
0赞 jamesdlin 3/1/2022
我认为这个答案应该澄清,这段代码实际上所做的是返回最接近四舍五入的值。double
0赞 Aditya Patil 6/19/2023
这不适用于 2.30
0赞 CopsOnRoad 6/20/2023
@AdityaPatil 什么行不通?你想要什么圆?2.30
3赞 Magnus 12/10/2020 #13

如果当生成的小数都是零时,您不需要任何小数,那么这样就可以了:

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 位小数。99.009.004

评论

0赞 SilSur 4/3/2023
我不知道为什么你们在问题明确指出时都给出截断的解决方案 ->How do you round a double in Dart to a given degree of precision ...
11赞 Muhammad Umair Saqib 1/29/2021 #14
double value = 2.8032739273;
String formattedValue = value.toStringAsFixed(3);

评论

2赞 Kardi Teknomo 1/29/2021
请在您的答案中添加更多解释,以方便其他用户
0赞 tgdavies 1/30/2021
这在语法上不正确,需要一个参数toStringAsFixed
2赞 Rahul Dev Garg 1/31/2021 #15

只需将此扩展写在双

extension Round on double {
  double roundToPrecision(int n) {
    int fac = pow(10, n).toInt();
    return (this * fac).round() / fac;
  }
}

评论

1赞 Gábor 5/25/2021
但是您显然需要对 . 返回 a ,而不是 .所以。int facpow()numinttoInt()
0赞 Rahul Dev Garg 7/18/2022
解决了问题
2赞 Mayb3Not 2/6/2021 #16

我认为公认的答案不是完美的解决方案,因为它转换为 .string

如果您不想从 GetX 包转换和转换回使用。stringdoubledouble.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);
  }
}
0赞 SilSur 3/28/2021 #17

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的代码 - 它用更精简的代码正确地解决了这个问题。

评论

0赞 SilSur 12/17/2021
更新函数(上):返回!!@deep沙阿roundAccurately(73.4750, 2)73.48
2赞 Paul 2/27/2022
这是非常复杂的。看看这个答案,只使用:Decimal.parse(this.toString()).round(scale: places).toDouble()
0赞 SilSur 4/30/2022
@Paul - 所以你想用一个超过 300 行代码的第三方库 [ github.com/a14n/dart-decimal/blob/master/lib/decimal.dart ] 替换一个有 63 行代码的独立函数?嗯。。。另外,您是否在 Dartpad.dev 年尝试过使用此库进行快速试用?(祝你好运!!...但我想每个人都有自己的。
0赞 Dani 12/7/2022
除了从头开始重写 Dart 之外,没有其他解决方案??
0赞 Dani 12/7/2022
实际上,我发布了另一个解决方案
6赞 luke77 5/12/2021 #18

您可以创建一个可重用的函数,该函数接受要格式化的 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

评论

2赞 SilSur 4/3/2023
干得好 - >您的解决方案完美运行(舍入 + 遵守舍入规则),并且您的代码比我的解决方案精简得多。所以我放弃了我的解决方案给你 - 谢谢你的努力。two thumbs up ]
0赞 jamesdlin 4/3/2023
.toStringAsFixed() 确实将以 5 结尾的数字四舍五入; 是 , 是 , 是 和 是 。正如此答案链接到的线程所解释的那样,通常不会发生这种情况的原因是 s 在表示十进制数时本质上是不精确的。例如,2.275 实际上是 2.274999999999999991182158029987476766109466552734375。0.5.toStringAsFixed(0)'1'0.25.toStringAsFixed(1)'0.3'0.125.toStringAsFixed(2)'0.13'doubledouble
0赞 Hoang 10/31/2023
roundOffToXDecimal(8.5) 到 8.51
0赞 SilSur 11/1/2023
@jamesdlin 是的,按照您指出的四舍五入,但它肯定不符合四舍五入规则。因此,让我们就此达成一致,这将阻止我们在这个问题上无休止地兜圈子。我认为卢克的解决方案在让我们到达我们想去的地方方面做得很好。:)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
0赞 jamesdlin 11/2/2023
@SilSur 您的规则是几种可能的舍入规则之一。你不能保证这个答案总是按照这个规则四舍五入。正如我所说,2.275 作为双倍实际上是 2.27499999999999999911182158029987476766109466552734375,所以这意味着此代码正在四舍五入 2.27499999999999999911182158029987476766109466552734375,即使它小于 2.275。(同样,当它被四舍五入时,它实际上并没有四舍五入到 2.28,这并不完全可以表示为 .它四舍五入为 2.2799999999999999804600747665972448885440826416015625。double
2赞 Thanapol Thong-art 6/22/2021 #19

如果使用动态类型的数据。你可以使用它。

 typeDecimal(data) => num.parse(data.toString()).toStringAsFixed(2);
15赞 Reza Taghizadeh 7/23/2021 #20

您可以简单地将该值乘以 100,然后四舍五入,然后再除以 100。

(number * 100).round() / 100.0;
2赞 Abu Bakar 8/14/2021 #21

此外,如果您想在文本中舍入双精度值。

文本('${carpetprice.toStringAsFixed(3)}',),

3赞 jamesdlin 8/30/2021 #22

如果要获得结果,将 IEEE-754 二进制浮点数四舍五入到特定数量的十进制数字本身就存在问题。doubledouble

就像像 1/3 这样的分数不能用有限数量的十进制数字精确表示一样,许多(嗯,无限多)十进制数不能用有限数量的二进制数字表示。例如,十进制数 0.1 不能用二进制精确表示。虽然您可以尝试将 0.09999 四舍五入为 0.1,但它实际上会“四舍五入”为 0.10000000000000000055511151231257827021181583404541015625。大多数其他声称具有十进制精度的舍入 s 的答案实际上返回最接近的可表示对象。当您通过将这些值转换为 s 来向用户显示这些值时,您可能会看到比预期更多的数字。doubledoubledoubleString

你可以做的是,当你最终向用户显示字符串表示时,它看起来像一个漂亮的四舍五入数字,这就是double.toStringAsFixed()的作用。这也是为什么当你打印 0.100000000...时,你可能会看到实现是否试图漂亮地打印用户友好的值。但是,不要被愚弄:该值实际上永远不会完全是 0.1,如果您使用如此不精确的值进行重复算术运算,则可能会累积误差(例如:0.1 + 0.2)。0.1double

请注意,以上所有内容都是二进制浮点数工作方式的基础,并非特定于 Dart。另请参阅:

底线:如果您关心十进制精度,请不要使用二进制浮点类型。如果您要处理金钱,这一点尤其重要。

您应该改用:

  • 整数。例如,如果您正在处理货币,则使用 ,而不是使用 。然后,您的计算将始终是准确的,并且只有在向用户显示它们时才能转换为所需的单位(同样,在读取用户的输入时也可以以相反的方向进行转换)。double dollars = 1.23;int cents = 123;
  • 一种类型,旨在以任意精度表示十进制数。例如,package:decimal 提供了一个类型。对于这种类型,其他一些答案(例如乘以 100、四舍五入,然后除以 100)将是合适的。(但实际上你应该直接使用 Decimal.roundDecimal

评论

0赞 Paul 2/27/2022
要使用此包准确四舍五入,请使用:Decimal.parse(this.toString()).round(scale: places).toDouble()
0赞 jamesdlin 2/28/2022
@Paul 您应该删除 .这违背了使用 .toDouble()package:decimal
0赞 Paul 2/28/2022
在某些情况下,双重回报可能会受到质疑,所以我认为我应该添加它。另外:这会正确地舍入双精度(可能只有一次)。但是,是的,如果您需要使用双精度/小数进行计算,则显然不应该这样做。
0赞 jamesdlin 2/28/2022
@Paul“正确舍入双精度”是一个荒谬的说法,因为你不能用以 10 为基数的数字来精确地舍入 a。从根本上说,有些以 10 为基数的数字不能精确地表示为 s。任何“四舍五入”都无法避免这种情况。doubledouble
6赞 Shawn Ashton 9/25/2021 #23

我在双倍上做了这个扩展

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");
    });
  });
}
-2赞 Michael 12/5/2021 #24

我像这样转换我=> `

num.tryParse("23.123456789")!.toDouble().roundToDouble()

`

-1赞 Dinesh Prajapati 12/7/2021 #25

你可以调用这个函数来获得 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; }
0赞 Nikolay 4/18/2022 #26

如果需要,请使用特殊的舍入。您可以尝试此函数(舍入)。

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
0赞 Rens 6/24/2022 #27

如果您需要适当的四舍五入(当第一位数字为 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
1赞 Dani 12/7/2022 #28

从没想过这在 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);

评论

1赞 jamesdlin 2/15/2023
与几乎所有其他答案一样,此答案应阐明此代码实际执行的操作是返回最接近截断值的值,因此当您将其转换回 时,最终可能会得到比预期多得多的数字。本质上不可能用二进制精确表示大多数小数十进制数。doubleString
0赞 SilSur 4/3/2023
@Dani - 此解决方案也不符合基本舍入规则 -> 返回,而不是 的正确值。@jamesdlin - 好吧......向我们提供您的解决方案(或至少尝试制定解决方案),而不是仅仅驳回其他人试图找到解决这个“众所周知”的舍入问题的尝试。truncateDouble(73.4750, 2)73.4773.48
0赞 jamesdlin 4/3/2023
@SilSur我已经提供了自己的答案。此外,我很难将建议澄清称为“击落”答案。
0赞 hashinclude72 10/6/2023 #29
double roundOffToXDecimal(num number, {int precision = 2}) {
  var precisionWithPow10 = pow(10, precision);
  return (number * precisionWithPow10).round() / precisionWithPow10;

评论

1赞 Jeremy Caney 10/7/2023
感谢您有兴趣为 Stack Overflow 社区做出贡献。这个问题已经有了不少答案,包括一个已经得到社区广泛验证的答案。你确定你的方法以前没有给出过吗?如果是这样,解释一下你的方法有何不同,在什么情况下你的方法可能更受欢迎,和/或为什么你认为前面的答案是不够的,这将是有用的。你能编辑你的答案以提供解释吗?