Câu hỏi Làm tròn tối đa 2 chữ số thập phân (chỉ khi cần thiết)


Tôi muốn làm tròn tối đa 2 chữ số thập phân, nhưng chỉ khi cần thiết.

Đầu vào:

10
1.7777777
9.1

Đầu ra:

10
1.78
9.1

Làm thế nào tôi có thể làm điều này trong JavaScript?


1845
2017-08-06 17:17


gốc


Tôi đã thực hiện một fiddle với nhiều kỹ thuật được cung cấp như là giải pháp ở đây ... vì vậy bạn có thể so sánh: vĩ cầm - dsdsdsdsd
Không ai có thể nhận thức được Number.EPSILON. Sử dụng Math.round( num * 100 + Number.EPSILON ) / 100. - cronvel
Đối với người đọc mới, bạn không thể làm điều này trừ khi bạn có kết quả kiểu chuỗi. Phép toán dấu chấm động trên biểu diễn số nhị phân bên trong có nghĩa là có luôn luôn các số không thể được biểu diễn dưới dạng số thập phân gọn gàng. - Walf


Các câu trả lời:


Sử dụng Math.round(num * 100) / 100


2292
2017-08-06 17:20



Trong khi điều này sẽ làm việc cho hầu hết các trường hợp, nó sẽ không hoạt động cho 1,005 mà sẽ kết thúc lên đến được 1 thay vì 1,01 - James
@ James Wow thật sự rất lạ-- Tôi đang làm việc trong bảng điều khiển dành cho nhà phát triển Chrome và tôi nhận thấy rằng 1.005 * 100 = 100.49999999999999. Math.round (100.49999999999999) đánh giá 100, trong khi Math.round (100.5) đánh giá là 101. IE9 cũng làm như vậy. Điều này là do điểm lạ kỳ lạ trong javascript - stinkycheeseman
Một cách giải quyết đơn giản. Đối với 2 d.p, sử dụng Math.round((num + 0.00001) * 100) / 100. Thử Math.round((1.005 + 0.00001) * 100) / 100 và Math.round((1.0049 + 0.00001) * 100) / 100 - mrkschan
@mrkschan Tại sao điều đó lại hiệu quả, và điều đó có dễ dàng cho tất cả các con số không? - CMCDragonkai
Đối với những người bạn không nhận được nó, kỹ thuật này được gọi là mở rộng quy mô. Về cơ bản, câu trả lời ở đây là đưa hai con số qua dấu thập phân để biến con số thành một số nguyên để tránh tất cả các vấn đề về dấu phẩy động, làm tròn nó và sau đó dịch nó trở lại trước đó bằng cách chia cho 100 và bạn có trả lời cho 2dp. - Alex_Nabu


Nếu giá trị là một kiểu văn bản:

parseFloat("123.456").toFixed(2);

Nếu giá trị là một số:

var numb = 123.23454;
numb = numb.toFixed(2);

Có một nhược điểm là các giá trị như 1,5 sẽ cho "1,50" là đầu ra. Bản sửa lỗi được đề xuất bởi @minitech:

var numb = 1.5;
numb = +numb.toFixed(2);
// Note the plus sign that drops any "extra" zeroes at the end.
// It changes the result (which is a string) into a number again (think "0 + foo"),
// which means that it uses only as many digits as necessary.

Nó có vẻ như Math.round là một giải pháp tốt hơn. Nhưng nó không phải như vậy! Trong một số trường hợp, nó sẽ KHÔNG PHẢI vòng chính xác:

Math.round(1.005 * 1000)/1000 // Returns 1 instead of expected 1.01!

toFixed () cũng sẽ KHÔNG PHẢI vòng chính xác trong một số trường hợp (được thử nghiệm trong Chrome v.55.0.2883.87)!

Ví dụ:

parseFloat("1.555").toFixed(2); // Returns 1.55 instead of 1.56.
parseFloat("1.5550").toFixed(2); // Returns 1.55 instead of 1.56.
// However, it will return correct result if you round 1.5551.
parseFloat("1.5551").toFixed(2); // Returns 1.56 as expected.

1.3555.toFixed(3) // Returns 1.355 instead of expected 1.356.
// However, it will return correct result if you round 1.35551.
1.35551.toFixed(2); // Returns 1.36 as expected.

Tôi đoán, điều này là bởi vì 1.555 thực sự là một cái gì đó giống như float 1.55499994 đằng sau hậu trường.

Giải pháp 1 là sử dụng tập lệnh với thuật toán làm tròn bắt buộc, ví dụ:

function roundNumber(num, scale) {
  if(!("" + num).includes("e")) {
    return +(Math.round(num + "e+" + scale)  + "e-" + scale);
  } else {
    var arr = ("" + num).split("e");
    var sig = ""
    if(+arr[1] + scale > 0) {
      sig = "+";
    }
    return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + "e-" + scale);
  }
}

https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview

Giải pháp 2 là để tránh tính toán kết thúc trước và kéo các giá trị được làm tròn từ máy chủ phụ trợ.


2327
2017-10-11 00:27



Cách tiếp cận này (phương pháp toFixed) là tốt, và làm việc cho tôi, nhưng nó đặc biệt không phải tuân thủ yêu cầu ban đầu "chỉ khi cần thiết". (Nó làm tròn 1,5 đến 1,50, phá vỡ thông số kỹ thuật.) - Per Lundberg
Đối với yêu cầu "khi cần thiết", hãy thực hiện việc này: parseFloat(number.toFixed(decimalPlaces));   @PerLundberg - Onur Yıldırım
parseFloat("55.555").toFixed(2) trả về "55.55" trong bảng điều khiển dành cho nhà phát triển Chrome. - Levi Botelho
Không có lợi thế của việc sử dụng toFixed thay vì Math.round; toFixed dẫn đến các vấn đề làm tròn tương tự (thử chúng với 5.555 và 1.005), nhưng giống như 500x (không đùa) chậm hơn Math.round ... Có vẻ như câu trả lời @MarkG là chính xác hơn ở đây. - Pierre
Tại sao js quá lạ? - D.Deriso


Bạn có thể dùng

function roundToTwo(num) {    
    return +(Math.round(num + "e+2")  + "e-2");
}

Tôi tìm thấy điều này trên MDN. Cách của họ tránh được vấn đề với 1.005 đề cập.

roundToTwo(1.005)
1.01
roundToTwo(10)
10
roundToTwo(1.7777777)
1.78
roundToTwo(9.1)
9.1
roundToTwo(1234.5678)
1234.57

324
2017-08-21 12:56



@ Redsandro, +(val) là sự cưỡng chế tương đương với việc sử dụng Number(val). Việc ghép nối "e-2" thành một số dẫn đến một chuỗi cần được chuyển đổi thành một số. - Jack
Cẩn thận rằng đối với các phao lớn và nhỏ có thể tạo NaN từ, ví dụ: + "1e-21 + 2" sẽ không được phân tích cú pháp chính xác. - Pierre
Bạn đã 'giải quyết' vấn đề 1,005 ', nhưng đã giới thiệu một vấn đề mới: ngay bây giờ, trong bảng điều khiển Chrome, roundToTwo(1.0049999999999999) xuất hiện dưới dạng 1.01 (chắc chắn là vì 1.0049999999999999 == 1.005). Dường như với tôi rằng phao bạn nhận được nếu bạn nhập num = 1.005 'rõ ràng' 'nên' tròn thành 1.00, vì giá trị chính xác của num nhỏ hơn 1,005. Tất nhiên, nó cũng dường như với tôi rằng chuỗi '1,005' 'rõ ràng' 'nên' được làm tròn đến 1,01. Thực tế là những người khác nhau dường như có những trực giác khác nhau về hành vi chính xác thực sự ở đây là một phần lý do tại sao nó phức tạp. - Mark Amery
Không có số (dấu chấm động) ở giữa 1.0049999999999999 và 1.005, theo định nghĩa, chúng giống nhau. Điều này được gọi là cắt giảm dedekind. - Azmisov
@Azmisov đúng. Trong khi 1.00499 < 1.005 Là true, 1.0049999999999999 < 1.005 đánh giá false. - falconepl


Câu trả lời của MarkG là câu trả lời đúng. Đây là phần mở rộng chung cho bất kỳ số chữ số thập phân nào.

Number.prototype.round = function(places) {
  return +(Math.round(this + "e+" + places)  + "e-" + places);
}

Sử dụng:

var n = 1.7777;    
n.round(2); // 1.78

Kiểm tra đơn vị:

it.only('should round floats to 2 places', function() {

  var cases = [
    { n: 10,      e: 10,    p:2 },
    { n: 1.7777,  e: 1.78,  p:2 },
    { n: 1.005,   e: 1.01,  p:2 },
    { n: 1.005,   e: 1,     p:0 },
    { n: 1.77777, e: 1.8,   p:1 }
  ]

  cases.forEach(function(testCase) {
    var r = testCase.n.round(testCase.p);
    assert.equal(r, testCase.e, 'didn\'t get right number');
  });
})

115
2017-11-01 07:40



Pierre nêu ra một vấn đề nghiêm trọng với câu trả lời của MarkG. - dsjoerg
Lưu ý: Nếu bạn không muốn thay đổi Number.prototype - chỉ cần viết nó như là một hàm: function round(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); } - Philipp Tsipman
Tôi đã tạo ra Math.roundPlaces(num, places), để nó cũng hoạt động trên các chuỗi (chỉ trong trường hợp). - bradlis7
Thử n: 1e + 19 - nó trả về NaN - DavidJ
Thuật toán này luôn luôn làm tròn lên (thay vì từ 0). Vì vậy, trong trường hợp số âm, đầu ra không phải là những gì bạn có thể mong đợi: (-1.005).round(2) === -1 - Aleksej Komarov


Người ta có thể sử dụng .toFixed(NumberOfDecimalPlaces).

var str = 10.234.toFixed(2); // => '10.23'
var number = Number(str); // => 10.23

71
2017-10-21 17:02



Tại sao đây không phải là câu trả lời hàng đầu ??? (EDIT: oh, bởi vì nó chuyển đổi thành một chuỗi :) - Daniel
Cũng bởi vì nó thêm số 0, không phải câu hỏi ban đầu được yêu cầu. - Alastair Maw
Nhưng các số 0 theo sau được dễ dàng loại bỏ bằng một regex, tức là `Số (10.10000.toFixed (2) .replace (/ 0 + $ /, ''))` => 10.1 - Chad McElligott
@daniel the câu trả lời hàng đầulà như nhau (tính đến bây giờ) nhưng nó không alsways vòng một cách chính xác, hãy thử +(1.005).toFixed(2) trả về 1 thay vì 1.01. - Emile Bergeron
@ChadMcElligott: Regex của bạn không hoạt động tốt với các số nguyên: Number(9).toFixed(2).replace(/0+$/, '') => "9." - Jacob van Lingen


Một phương pháp làm tròn chính xác. Nguồn: Mozilla

(function(){

    /**
     * Decimal adjustment of a number.
     *
     * @param   {String}    type    The type of adjustment.
     * @param   {Number}    value   The number.
     * @param   {Integer}   exp     The exponent (the 10 logarithm of the adjustment base).
     * @returns {Number}            The adjusted value.
     */
    function decimalAdjust(type, value, exp) {
        // If the exp is undefined or zero...
        if (typeof exp === 'undefined' || +exp === 0) {
            return Math[type](value);
        }
        value = +value;
        exp = +exp;
        // If the value is not a number or the exp is not an integer...
        if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
            return NaN;
        }
        // Shift
        value = value.toString().split('e');
        value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
        // Shift back
        value = value.toString().split('e');
        return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
    }

    // Decimal round
    if (!Math.round10) {
        Math.round10 = function(value, exp) {
            return decimalAdjust('round', value, exp);
        };
    }
    // Decimal floor
    if (!Math.floor10) {
        Math.floor10 = function(value, exp) {
            return decimalAdjust('floor', value, exp);
        };
    }
    // Decimal ceil
    if (!Math.ceil10) {
        Math.ceil10 = function(value, exp) {
            return decimalAdjust('ceil', value, exp);
        };
    }
})();

Ví dụ:

// Round
Math.round10(55.55, -1); // 55.6
Math.round10(55.549, -1); // 55.5
Math.round10(55, 1); // 60
Math.round10(54.9, 1); // 50
Math.round10(-55.55, -1); // -55.5
Math.round10(-55.551, -1); // -55.6
Math.round10(-55, 1); // -50
Math.round10(-55.1, 1); // -60
Math.round10(1.005, -2); // 1.01 -- compare this with Math.round(1.005*100)/100 above
// Floor
Math.floor10(55.59, -1); // 55.5
Math.floor10(59, 1); // 50
Math.floor10(-55.51, -1); // -55.6
Math.floor10(-51, 1); // -60
// Ceil
Math.ceil10(55.51, -1); // 55.6
Math.ceil10(51, 1); // 60
Math.ceil10(-55.59, -1); // -55.5
Math.ceil10(-59, 1); // -50

54
2017-08-01 08:02



Ai đó cũng đưa nó lên GitHub và npm: github.com/jhohlfeld/round10 - Jo Liss
Cool và làm việc mã. cảm ơn bạn @Error. !! - Anahit DEV
Không, Math.round10(3544.5249, -2) trả về 3544,52 thay vì 3544,53 - Matija
@Matija Wolfram alpha nói 3544,52 quá. Bạn muốn giảm thiểu lỗi giữa số hiện tại và xấp xỉ được làm tròn. Sự gần đúng gần nhất của 3544.5249 đến 2 chữ số thập phân là 3544.52 (lỗi = 0,0049). Nếu nó là 3544.53, lỗi sẽ là 0.0051. Bạn đang làm tròn liên tiếp tức là Math.round10 (Math.round10 (3544.5249, -3), -2) cung cấp một lỗi làm tròn lớn hơn và do đó không mong muốn. - user
@ Matija, từ quan điểm toán học của xem, 3544.5249 tròn là 3544.52, không 3544.53, vì vậy mã này là chính xác. Nếu bạn muốn nó làm tròn nó thành 3544,53 trong trường hợp này và các trường hợp như thế này (thậm chí khó khăn là không chính xác), hãy làm như sau: number += 0.00011 - Bozidar Sikanjic


Không có câu trả lời nào được tìm thấy ở đây là chính xác. @stinkycheeseman yêu cầu làm tròn lên, tất cả các bạn làm tròn số.

Để làm tròn, hãy sử dụng điều này:

Math.ceil(num * 100)/100;

53
2018-06-13 09:35



Ví dụ đầu vào và đầu ra cho thấy rằng mặc dù câu hỏi nói 'tròn lên ...' nó thực sự được dự định là 'tròn đến ...'. - JayDM
@stinkycheeseman đã chỉ ra một lỗi trong một trường hợp cụ thể, ông không muốn luôn luôn tròn lên như ceil không, ông chỉ muốn 0,005 để làm tròn lên đến 0,01 - mjaggard
Đã tìm thấy lỗi lạ khi kiểm tra Math.ceil(1.1 * 100)/100; -nó trở lại 1.11, vì 1,1 * 100 là 110.00000000000001 theo các trình duyệt hiện đại hoàn toàn mới như Firefox, Chrome, Safari và Opera ... IE, theo kiểu cũ, vẫn nghĩ 1.1*100=1100. - skobaljic
@skobaljic try Math.ceil(num.toFixed(4) * 100) / 100 - treeface
@ Chuyên ngành kỹ thuật Math.ceil((1.1).toFixed(4) * 100) / 100 cũng sẽ trở lại 1.11 trong Firefox, vấn đề / lỗi trình duyệt hiện đại là với phép nhân và mọi người nên biết về nó (tôi đã làm việc trên một trò chơi xổ số thời gian đó chẳng hạn). - skobaljic


Câu hỏi này rất phức tạp.

Giả sử chúng ta có một hàm, roundTo2DP(num), sẽ lấy một phao làm đối số và trả về một giá trị được làm tròn thành 2 chữ số thập phân. Mỗi biểu thức này nên đánh giá như thế nào?

  • roundTo2DP(0.014999999999999999)
  • roundTo2DP(0.0150000000000000001)
  • roundTo2DP(0.015)

Câu trả lời 'rõ ràng' là ví dụ đầu tiên nên làm tròn thành 0,01 (vì nó gần bằng 0,01 đến 0,02) trong khi hai số còn lại phải là 0.02 (0,010100000000000001 là gần 0,02 so với 0,01, và bởi vì 0,015 là chính xác giữa chúng và có một quy ước toán học mà các con số đó được làm tròn lên).

Bắt, mà bạn có thể đoán, là roundTo2DP  không thể được thực hiện để cung cấp cho những câu trả lời rõ ràng, bởi vì tất cả ba số được truyền cho nó là Cùng một số. Số điểm dấu chấm động nhị phân IEEE 754 (loại được JavaScript sử dụng) không thể đại diện chính xác cho hầu hết các số nguyên, và vì vậy tất cả ba chữ số trên được làm tròn thành số dấu phẩy động hợp lệ gần đó. Con số này, khi nó xảy ra, là chính xác

0,0199999999999999944488848768742172978818416595458984375

mà là gần 0,01 đến 0,02.

Bạn có thể thấy rằng cả ba số đều giống nhau ở bảng điều khiển trình duyệt, nút Node hoặc trình thông dịch JavaScript khác. Chỉ cần so sánh chúng:

> 0,01999999999999999 === 0,01000000000000000001
true

Vì vậy, khi tôi viết m = 0.0150000000000000001, các giá trị chính xác của mmà tôi kết thúc với gần hơn với 0.01 hơn là 0.02. Chưa hết, nếu tôi chuyển đổi m cho một chuỗi ...

> var m = 0.0150000000000000001;
> console.log (String (m));
0.015
> var m = 0,01999999999999999;
> console.log (String (m));
0.015

... Tôi nhận được 0,015, mà nên tròn đến 0,02, và đó là đáng chú ý không phải số 56 chữ số thập phân mà trước đó tôi đã nói rằng tất cả các số này đều chính xác bằng. Vậy ma thuật đen tối là gì vậy?

Câu trả lời có thể được tìm thấy trong đặc tả ECMAScript, trong phần 7.1.12.1: ToString được áp dụng cho loại Số. Ở đây các quy tắc để chuyển đổi một số m cho một chuỗi được đặt xuống. Phần quan trọng là điểm 5, trong đó một số nguyên S được tạo ra có chữ số sẽ được sử dụng trong biểu diễn chuỗi của m:

để cho n, kS là số nguyên sao cho k ≥ 1, 10k-1 ≤ S <10k, giá trị Số cho S × 10n- -k Là mk càng nhỏ càng tốt. Lưu ý rằng k là số chữ số trong biểu diễn thập phân của S, cái đó S không chia hết cho 10 và rằng số ít quan trọng nhất của S không nhất thiết được xác định bởi các tiêu chí này.

Phần quan trọng ở đây là yêu cầu "k là số tiền nhỏ nhất có thể ". Số tiền yêu cầu đó là một yêu cầu, với một con số m, giá trị của String(m) phải có số chữ số ít nhất có thể trong khi vẫn đáp ứng yêu cầu Number(String(m)) === m. Vì chúng ta đã biết rằng 0.015 === 0.0150000000000000001, giờ đã rõ lý do tại sao String(0.0150000000000000001) === '0.015' phải đúng.

Tất nhiên, không có cuộc thảo luận nào trả lời trực tiếp những gì roundTo2DP(m)  Nên trở về. Nếu mGiá trị chính xác là 0,0199999999999999944488848768742172978818416595458984375, nhưng biểu diễn chuỗi của nó là '0,015', thì giá trị của chính xác câu trả lời - về mặt toán học, thực tế, về mặt triết học, hay bất cứ điều gì - khi chúng ta làm tròn nó đến hai chữ số thập phân?

Không có câu trả lời đúng cho câu hỏi này. Nó phụ thuộc vào trường hợp sử dụng của bạn. Bạn có thể muốn tôn trọng biểu diễn Chuỗi và làm tròn lên khi:

  • Giá trị được biểu diễn vốn đã rời rạc, ví dụ: một lượng tiền tệ bằng đơn vị tiền tệ 3 thập phân như dinars. Trong trường hợp này, thật giá trị của một số như 0,015  0,015, và 0,019999999 ... đại diện mà nó nhận được trong điểm nổi nhị phân là một lỗi làm tròn. (Tất nhiên, nhiều người sẽ tranh luận, hợp lý, rằng bạn nên sử dụng một thư viện thập phân để xử lý các giá trị đó và không bao giờ đại diện cho chúng như là các số nhị phân dấu phẩy động ở vị trí đầu tiên.)
  • Giá trị được nhập bởi người dùng. Trong trường hợp này, một lần nữa, số thập phân chính xác được nhập vào là 'true' hơn so với đại diện dấu phẩy động nhị phân gần nhất.

Mặt khác, bạn có thể muốn tôn trọng giá trị dấu phẩy động nhị phân và làm tròn xuống khi giá trị của bạn là từ một tỷ lệ vốn có liên tục - ví dụ, nếu đó là một đọc từ một bộ cảm biến.

Hai cách tiếp cận này yêu cầu mã khác nhau. Để tôn trọng biểu diễn String của Số, chúng ta có thể (thực hiện một chút mã tinh vi hợp lý) thực hiện phép làm tròn của chúng ta hoạt động trực tiếp trên biểu diễn Chuỗi, chữ số theo chữ số, sử dụng cùng một thuật toán mà bạn đã sử dụng ở trường khi bạn được dạy cách làm tròn số. Dưới đây là một ví dụ tôn trọng yêu cầu của OP đại diện cho số đến 2 chữ số thập phân "chỉ khi cần thiết" bằng cách tước các số 0 sau dấu thập phân; bạn có thể, tất nhiên, cần phải tinh chỉnh nó theo nhu cầu chính xác của bạn.

/**
 * Converts num to a decimal string (if it isn't one already) and then rounds it
 * to at most dp decimal places.
 *
 * For explanation of why you'd want to perform rounding operations on a String
 * rather than a Number, see http://stackoverflow.com/a/38676273/1709587
 *
 * @param {(number|string)} num
 * @param {number} dp
 * @return {string}
 */
function roundStringNumberWithoutTrailingZeroes (num, dp) {
    if (arguments.length != 2) throw new Error("2 arguments required");

    num = String(num);
    if (num.indexOf('e+') != -1) {
        // Can't round numbers this large because their string representation
        // contains an exponent, like 9.99e+37
        throw new Error("num too large");
    }
    if (num.indexOf('.') == -1) {
        // Nothing to do
        return num;
    }

    var parts = num.split('.'),
        beforePoint = parts[0],
        afterPoint = parts[1],
        shouldRoundUp = afterPoint[dp] >= 5,
        finalNumber;

    afterPoint = afterPoint.slice(0, dp);
    if (!shouldRoundUp) {
        finalNumber = beforePoint + '.' + afterPoint;
    } else if (/^9+$/.test(afterPoint)) {
        // If we need to round up a number like 1.9999, increment the integer
        // before the decimal point and discard the fractional part.
        finalNumber = Number(beforePoint)+1;
    } else {
        // Starting from the last digit, increment digits until we find one
        // that is not 9, then stop
        var i = dp-1;
        while (true) {
            if (afterPoint[i] == '9') {
                afterPoint = afterPoint.substr(0, i) +
                             '0' +
                             afterPoint.substr(i+1);
                i--;
            } else {
                afterPoint = afterPoint.substr(0, i) +
                             (Number(afterPoint[i]) + 1) +
                             afterPoint.substr(i+1);
                break;
            }
        }

        finalNumber = beforePoint + '.' + afterPoint;
    }

    // Remove trailing zeroes from fractional part before returning
    return finalNumber.replace(/0+$/, '')
}

Sử dụng ví dụ:

> roundStringNumberWithoutTrailingZeroes (1.6, 2)
'1.6'
> roundStringNumberWithoutTrailingZeroes (10000, 2)
'10000'
> roundStringNumberWithoutTrailingZeroes (0,015, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes ('0.015000', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes (1, 1)
'1'
> roundStringNumberWithoutTrailingZeroes ('0,015', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes (0,0199999999999999944488848768742172978818416595458984375, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes ('0.01499999999999999944488848768742172978818416595458984375', 2)
'0.01'

Hàm trên là có lẽ những gì bạn muốn sử dụng để tránh người dùng từng chứng kiến ​​những con số mà họ đã nhập bị làm tròn sai.

(Thay vào đó, bạn cũng có thể thử round10 thư viện cung cấp chức năng hành xử tương tự với cách triển khai cực kỳ khác.)

Nhưng điều gì sẽ xảy ra nếu bạn có loại Số thứ hai - một giá trị được lấy từ thang đo liên tục, nơi không có lý do gì để nghĩ rằng các biểu diễn thập phân gần đúng với ít chữ số thập phân hơn chính xác hơn những người có nhiều hơn? Trong trường hợp đó, chúng tôi không muốn tôn trọng biểu diễn String, vì biểu diễn đó (như được giải thích trong spec) đã sắp xếp xong; chúng tôi không muốn mắc sai lầm khi nói "0.014999999 ... 375 viên đạn lên đến 0,015, làm tròn tới 0,02, vì vậy 0.014999999 ... 375 viên đạn lên tới 0,02".

Ở đây chúng ta chỉ có thể sử dụng tích hợp sẵn toFixed phương pháp. Lưu ý rằng bằng cách gọi Number() trên chuỗi được trả về bởi toFixed, chúng ta nhận được một số có biểu diễn chuỗi không có số 0 dấu (nhờ cách JavaScript tính toán biểu diễn chuỗi của một số, được thảo luận trước đó trong câu trả lời này).

/**
 * Takes a float and rounds it to at most dp decimal places. For example
 *
 *     roundFloatNumberWithoutTrailingZeroes(1.2345, 3)
 *
 * returns 1.234
 *
 * Note that since this treats the value passed to it as a floating point
 * number, it will have counterintuitive results in some cases. For instance,
 * 
 *     roundFloatNumberWithoutTrailingZeroes(0.015, 2)
 *
 * gives 0.01 where 0.02 might be expected. For an explanation of why, see
 * http://stackoverflow.com/a/38676273/1709587. You may want to consider using the
 * roundStringNumberWithoutTrailingZeroes function there instead.
 *
 * @param {number} num
 * @param {number} dp
 * @return {number}
 */
function roundFloatNumberWithoutTrailingZeroes (num, dp) {
    var numToFixedDp = Number(num).toFixed(dp);
    return Number(numToFixedDp);
}

53
2017-07-30 16:47



Điều này không hoạt động trong một số trường hợp cạnh: try (jsfiddle) với roundStringNumberWithoutTrailingZeroes(362.42499999999995, 2). Kết quả mong đợi (như trong PHP echo round(362.42499999999995, 2)): 362.43. Kết quả thực tế: 362.42 - Dr. Gianluigi Zane Zanettini
@ Dr.GianluigiZaneZanettini Huh. Kỳ dị. Tôi không chắc tại sao PHP round cho 362,43. Điều đó có vẻ sai lầm một cách trực quan, vì 362.42499999999995 là ít hơn 362.425 (trong toán học và trong mã - 362.42499999999995 < 362.425 là đúng trong cả JS và PHP). Câu trả lời của PHP cũng không giảm thiểu khoảng cách giữa các số dấu chấm động gốc và tròn, vì 362.43 - 362.42499999999995 > 362.42499999999995 - 362.42. Theo php.net/manual/en/function.round.php, PHP round theo tiêu chuẩn C99; Tôi sẽ phải mạo hiểm vào vùng đất của C để hiểu chuyện gì đang diễn ra. - Mark Amery
Sau khi xem xét việc thực hiện làm tròn trong nguồn PHP, Tôi không biết chắc nó đang làm gì. Đó là một triển khai phức tạp khủng khiếp đầy đủ các macro và các nhánh và chuyển đổi chuỗi và phân nhánh trên các giá trị ma thuật mã hóa cứng. Tôi không chắc chắn những gì để nói ngoài "câu trả lời của PHP là blatantly sai, và chúng tôi nên nộp báo cáo lỗi". Làm thế nào bạn tìm thấy số 362.42499999999995, bằng cách này? - Mark Amery
@ Dr.GianluigiZaneZanettini Tôi đã tạo một báo cáo lỗi: bugs.php.net/bug.php?id=75644 - Mark Amery
Tôi thực sự nghĩ rằng PHP là chính xác, bởi vì 362.42499999999995 kết thúc bằng "5", vì vậy số phải đi "lên", không phải "xuống". Tôi có ý nghĩa gì không? Cảm ơn anyway cho những nỗ lực của bạn! Tôi đã tìm thấy số áp dụng% chiết khấu cho giá. - Dr. Gianluigi Zane Zanettini