给定一个double,我希望将它四舍五入到小数点后的给定精度点数,类似于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四舍五入的问题已经出现了很长一段时间(@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;
}

这是一个完全手动的方法(可能有点过度),但它是有效的。请测试一下(直到耗尽),如果我没有做到,请告诉我。

其他回答

您可以使用toStringAsFixed来显示小数点后的有限数字。toStringAsFixed返回一个小数字符串表示形式。toStringAsFixed接受一个名为fraction Digits的参数,它表示我们想要显示的小数后面的位数。下面是如何使用它。

double pi = 3.1415926;
const val = pi.toStringAsFixed(2); // 3.14

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

这种联系也有其他的解决方案

var price = 99.012334554;
price = price.toStringAsFixed(2);
print(price); // 99.01

这是dart的ref。 裁判:https://api.dartlang.org/stable/2.3.0/dart-core/num/toStringAsFixed.html

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

打印: 1.23

这个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;
}

这是一个完全手动的方法(可能有点过度),但它是有效的。请测试一下(直到耗尽),如果我没有做到,请告诉我。