给定一个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

随着数字大小的增加,小数点后的精度也相应降低。


当前回答

我使用toStringAsFixed()方法将一个数字四舍五入到小数点后的特定数字 例:

double num = 22.48132906

当我四舍五入到像这样的两个数字时:

print(num.toStringAsFixed(2)) ;

结果是22.48

当我四舍五入到一个数字时,它显示出22.5

其他回答

double value = 2.8032739273;
String formattedValue = value.toStringAsFixed(3);

我在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");
    });
  });
}

效果很好

var price=99.012334554
price = price.roundTodouble();
print(price); // 99.01

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

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

您可以调用此函数来获得黑暗(颤振)的精确程度。 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; }