[英]How to round a double up to a given degree of precision after the decimal point?
[英]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
隨着數字大小的增加,我相應地失去了小數點后的精度。
請參閱num.toStringAsFixed()的文檔。
字符串toStringAsFixed (int fractionDigits)
返回 this 的小數點字符串表示形式。
在計算字符串表示之前將其轉換為雙精度。
例子:
1000000000000000000000.toStringAsExponential(3); // 1.000e+21
參數 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
num.toStringAsFixed()
輪。 這會將您的 num (n) 轉換為具有您想要的小數位數 (2) 的字符串,然后在一行甜蜜的代碼中將其解析回您的 num:
n = num.parse(n.toStringAsFixed(2));
上述解決方案沒有適當地對數字進行四舍五入。 我用:
double dp(double val, int places){
num mod = pow(10.0, places);
return ((val * mod).round().toDouble() / mod);
}
直接方式:
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
}
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
void main() {
int decimals = 2;
int fac = pow(10, decimals);
double d = 1.234567889;
d = (d * fac).round() / fac;
print("d: $d");
}
打印:1.23
我使用了toStringAsFixed()
方法,將數字四舍五入到小數點 EX 后的特定數字:
double num = 22.48132906
當我將它四舍五入為這樣的兩個數字時:
print(num.toStringAsFixed(2)) ;
它打印22.48
當我四舍五入到一個數字時,它打印出22.5
@andyw 使用 Dart 擴展方法修改后的答案:
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
要將 Dart 中的 double 舍入到小數點后的給定精度,您可以使用 dart toStringAsFixed()
方法中的內置解決方案,但您必須將其轉換回 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
}
您可以簡單地將值乘以 100,然后將其四舍五入,然后再除以 100。
(number * 100).round() / 100.0;
double value = 2.8032739273;
String formattedValue = value.toStringAsFixed(3);
您可以使用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
您可以創建一個可重用的函數,該函數接受要格式化的 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;
number += 1 / (10 * pow(10, existingNumberOfDecimal));
}
return double.parse(number.toStringAsFixed(numberOfDecimal));
}
// Example of usage:
var price = roundOffToXDecimal(2.275, numberOfDecimal: 2)
print(price); // 2.28
我在雙重上做了這個擴展
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");
});
});
}
只需在 double 上寫這個擴展
extension Round on double {
double roundToPrecision(int n) {
int fac = pow(10, n).toInt();
return (this * fac).round() / fac;
}
}
我認為接受的答案不是完美的解決方案,因為它轉換為string
。
如果您不想轉換為string
並返回double
使用GetX包中的double.toPrecision(decimalNumber)
。
如果你不想僅僅為此使用 GetX(我強烈推薦 GetX,它會改變你的生活)你可以復制並粘貼它。
當您想使用擴展時,請記住導入文件。
import 'dart:math';
extension Precision on double {
double toPrecision(int fractionDigits) {
var mod = pow(10, fractionDigits.toDouble()).toDouble();
return ((this * mod).round().toDouble() / mod);
}
}
如果你想在文本中舍入雙精度值。
文本('${carpetprice.toStringAsFixed(3)}',),
將double
(一個 IEEE-754二進制浮點數)四舍五入到特定數量的十進制數字本質上是有問題的。
就像 1/3 這樣的分數不能用有限個十進制數字精確表示一樣,許多(實際上是無限多個)十進制數字也不能用有限個二進制數字表示。 例如,十進制數 0.1 不能用二進制精確表示。 雖然您可以嘗試將 0.09999 舍入為 0.1,但實際上將其“舍入”為double
。 聲稱以小數精度舍入double
的大多數其他答案實際上返回最接近的可表示double
。
您可以做的是使字符串表示看起來像一個漂亮的四舍五入數字,這就是double.toStringAsFixed()
所做的。 這也是為什么當您打印 0.100000000... 時,如果實現嘗試打印用戶友好的值,您可能會看到0.1
。 但是,不要被愚弄了: double
精度值實際上永遠不會是 0.1,如果你用這種不精確的值重復算術,你可能會累積錯誤。
請注意,以上所有內容都是浮點數工作方式所固有的,並不是 Dart 特有的。 另見:
底線:如果您關心十進制精度,請不要使用二進制浮點類型。 如果您正在處理金錢,這一點尤其重要。
您應該使用:
double dollars = 1.23;
, 使用int cents = 123;
. 然后,您的計算將始終是准確的,並且只有在向用戶顯示它們時才能轉換為所需的單位(並且同樣可以在讀取用戶的輸入時以相反的方向轉換)。package:decimal
提供了Decimal
類型。 對於這種類型,其他一些答案(例如乘以 100、四舍五入,然后除以 100)將是合適的。 (但實際上你應該直接使用Decimal.round
。)如果您在結果小數全為零時不想要任何小數,則可以使用以下方法:
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);
}
如果輸入是9.004
並且您想要 2 個小數,這將簡單地輸出9
而不是9.00
。
如果使用動態類型的數據。 你可以使用它。
typeDecimal(data) => num.parse(data.toString()).toStringAsFixed(2);
從沒想過這在 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);
這個 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;
print("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 ...
print("Result (AccuRound) => $dResFin !!"); // Deactivate this 'print()' line in production code !!
return dResFin;
}
這是一種完全手動的方法(可能有點矯枉過正),但它確實有效。 請測試它(用盡),如果我錯過了標記,請告訴我。
如果你想使用特殊的舍入。 你可以試試這個功能(四舍五入)。
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
我喜歡這樣轉換我的 => `
num.tryParse("23.123456789")!.toDouble().roundToDouble()
`
您可以調用此函數來獲得黑暗(顫動)的精確度。 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; }
這工作得很好
var price=99.012334554
price = price.roundTodouble();
print(price); // 99.01
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.