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

Luc*_*ows 49 precision double-precision dart

给定一个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
Run Code Online (Sandbox Code Playgroud)

随着数量的增加,我在小数位后相应地失去了精度.

Gre*_*owe 90

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

String toStringAsFixed(int fractionDigits)

返回此的小数点字符串表示形式.

在计算字符串表示之前将其转换为double.

如果this的绝对值大于或等于10 ^ 21,则此方法返回由this.toStringAsExponential()计算的指数表示.否则,结果是最接近的字符串表示,小数点后面的fractionDigits数字正好.如果fractionDigits等于0,则省略小数点.

参数fractionDigits必须是满足的整数:0 <= fractionDigits <= 20.

例子:

1000000000000000000000.toStringAsExponential(3); // 1.000e+21
Run Code Online (Sandbox Code Playgroud)

  • 我认为 toStringAsFixed() 是由于其不一致而使用的舍入方法。例如,尝试“5.550.toStringAsFixed(1)” (5认同)

Yng*_*and 35

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

n = num.parse(n.toStringAsFixed(2));
Run Code Online (Sandbox Code Playgroud)

  • 这是最快捷的方式.但dart没有直接的方法来做这件事是愚蠢的 (6认同)
  • 扩展方法:`extension NumberRounding on num { num toPrecision(int precision) { return num.parse((this).toStringAsFixed( precision)); } }` (3认同)
  • 进行了一些快速测量。toString 和解析比使用 POW 进行 1000 万次迭代的数学解决方案慢大约 50 倍。100 万次迭代时速度慢 25 倍,100000 次迭代时速度慢 10 倍。万一有人想知道,就像我一样。 (2认同)

Cop*_*oad 26

定义一个扩展:

extension Ex on double {
  double toPrecision(int n) => double.parse(toStringAsFixed(n));
}
Run Code Online (Sandbox Code Playgroud)

用法:

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
}
Run Code Online (Sandbox Code Playgroud)


San*_*dal 22

我使用了该toStringAsFixed()方法,将数字四舍五入为小数点 EX 后的特定数字:

double num = 22.48132906
Run Code Online (Sandbox Code Playgroud)

当我将它四舍五入为两个这样的数字时:

print(num.toStringAsFixed(2)) ;
Run Code Online (Sandbox Code Playgroud)

它打印 22.48

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


kub*_*ick 15

@andyw 使用 Dart 扩展方法修改后的答案:

extension Precision on double {
    double toPrecision(int fractionDigits) {
        double mod = pow(10, fractionDigits.toDouble());
        return ((this * mod).round().toDouble() / mod);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

var latitude = 1.123456;
var latitudeWithFixedPrecision = latitude.toPrecision(3); // Outputs: 1.123
Run Code Online (Sandbox Code Playgroud)


Ali*_*deh 15

您只需将该值乘以 100,然后四舍五入,然后再次除以 100。

(number * 100).round() / 100.0;
Run Code Online (Sandbox Code Playgroud)


and*_*dyw 14

上述解决方案没有适当地舍入数字。我用:

double dp(double val, int places){ 
   double mod = pow(10.0, places); 
   return ((val * mod).round().toDouble() / mod); 
}
Run Code Online (Sandbox Code Playgroud)

  • 不适用于 dp(73.4750, 2) 它返回 73.47 而不是 73.48 https://www.calculatorsoup.com/calculators/math/roundingnumbers.php?x=73.4750&amp;round=2&amp;action=solve 查看此链接 (3认同)

sul*_*rza 14

要将 Dart 中的 double 舍入到小数点后给定的精度,您可以使用 darttoStringAsFixed()方法中的内置解决方案,但您必须将其转换回 double

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
}

Run Code Online (Sandbox Code Playgroud)

  • 这个答案没有为 [Yngvar Natland 更早的答案](/sf/answers/2254365151/) 添加任何内容。另外,我认为这个答案应该澄清这个代码实际上所做的是将*最近的*“double”返回到四舍五入的值。 (2认同)

Rob*_*ert 11

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

印刷品:1.23

  • 这是目前最好的方法。舍入到像 0.01 这样本身不是双精度的精度,这不是微不足道的。结果甚至可能根本无法表示为双精度值。我强烈建议将整数用于小数精度很重要的任何事物(例如,金钱)。 (2认同)

Riz*_*sar 11

    var price=99.012334554;
price = price.toStringAsFixed(2);
print(price); // 99.01
Run Code Online (Sandbox Code Playgroud)

That is the ref of dart. ref: https://api.dartlang.org/stable/2.3.0/dart-core/num/toStringAsFixed.html


Muh*_*qib 9

double value = 2.8032739273;
String formattedValue = value.toStringAsFixed(3);
Run Code Online (Sandbox Code Playgroud)

  • 为了其他用户的利益,请在您的答案中添加更多解释 (2认同)

Had*_*Mir 8

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

double pi = 3.1415926;
const val = pi.toStringAsFixed(2); // 3.14
Run Code Online (Sandbox Code Playgroud)


luk*_*uke 6

您可以创建一个可重用的函数,接受要格式化的 numberOfDecimal 并利用 toStringAsFixed() 方法格式化数字并将其转换回 double

仅供参考,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
Run Code Online (Sandbox Code Playgroud)

  • 干得好 - &gt;您的解决方案完美运行(舍入+遵守舍入规则)并且您的代码比我的解决方案精简得多。所以我放弃了你的解决方案 - 感谢你的努力。[`竖起两个大拇指`] (2认同)

Sha*_*ton 6

我在 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

以下是通过的测试。

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");
    });
  });
}
Run Code Online (Sandbox Code Playgroud)


Run*_*sis 5

以上解决方案不适用于所有情况。对我的问题有用的是这个解决方案,它将把你的数字四舍五入(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);
Run Code Online (Sandbox Code Playgroud)

输出: 13

此链接也有其他解决方案