Bagaimana cara memformat float di javascript?

427

Dalam JavaScript, ketika mengkonversi dari float ke string, bagaimana saya bisa mendapatkan hanya 2 digit setelah titik desimal? Misalnya, 0,34 bukannya 0,3445434.

jww
sumber
16
Hanya beberapa pilihan: apakah Anda ingin 'memenggal' semua kecuali dua digit pertama, atau Anda ingin membulatkan ke dua digit?
xtofl

Jawaban:

232
var result = Math.round(original*100)/100;

Spesifikasinya , jika kodenya tidak jelas.

sunting: ... atau gunakan saja toFixed, seperti yang diusulkan oleh Tim Büthe . Lupa itu, terima kasih (dan upvote) untuk pengingat :)

kkyy
sumber
1
Saya menggunakan ini di perpustakaan "Highchart" di mana ia tidak menerima nilai string maka toFixed tidak bekerja untuk saya, Math.round menyelesaikan masalah saya, terima kasih
Swapnil Chincholkar
4
toFixed()akan meniru apa yang dilakukan sesuatu printf()dalam C. Namun, toFixed()dan Math.round()akan menangani pembulatan berbeda. Dalam hal ini, toFixed()akan memiliki efek yang sama Math.floor()akan (jika Anda mengalikan aslinya dengan 10 ^ n sebelumnya, dan menelepon toFixed()dengan n digit). "Kebenaran" jawabannya sangat tergantung pada apa yang diinginkan OP di sini, dan keduanya "benar" dengan caranya sendiri.
DDPWNAGE
838

Ada fungsi untuk membulatkan angka. Sebagai contoh:

var x = 5.0364342423;
print(x.toFixed(2));

akan mencetak 5.04.

EDIT: Fiddle

Tim Büthe
sumber
7
Saya akan merekomendasikan untuk tidak menggunakan print () di browser sekalipun
cobbal
70
Hati-hati dengan ini, toFixed () mengembalikan sebuah string: var x = 5.036432346; var y = x.toFixed(2) + 100; yakan sama"5.03100"
Vlad
5
Ketahuilah bahwa (1e100) .toFixed (2) === "1e + 100"
qbolec
7
Waspadalah terhadap pembulatan yang tidak konsisten: (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)...
Skippy le Grand Gourou
3
Jika Anda mencari yang setara dengan toFixed tetapi dengan pembulatan konsisten, gunakan toLocaleString: (0.345) .toLocaleString ('en-EN', {minimumFractionDigits: 2, maksimumFractionDigits: 2})
fred727
185

Hati-hati saat menggunakan toFixed():

Pertama, pembulatan angka dilakukan dengan menggunakan representasi biner dari angka tersebut, yang dapat menyebabkan perilaku yang tidak terduga. Sebagai contoh

(0.595).toFixed(2) === '0.59'

bukannya '0.6'.

Kedua, ada bug IE dengan toFixed(). Di IE (setidaknya hingga versi 7, tidak memeriksa IE8), hal berikut ini berlaku:

(0.9).toFixed(0) === '0'

Mungkin ide yang baik untuk mengikuti saran kkyy atau menggunakan toFixed()fungsi kustom , misalnya

function toFixed(value, precision) {
    var power = Math.pow(10, precision || 0);
    return String(Math.round(value * power) / power);
}
Christoph
sumber
Ya, ini bisa sangat penting ketika membuat kode untuk memprediksi harga. Terima kasih! +1
Fabio Milheiro
10
Saya akan menyarankan menambahkan .toFixed()metode asli dalam nilai kembali, yang akan menambah jumlah presisi yang diperlukan, misalnya: return (Math.round(value * power) / power).toFixed(precision);dan juga mengembalikan nilai sebagai string. Jika tidak, ketelitian 20 diabaikan untuk desimal yang lebih kecil
William Joss Crowcroft
3
Satu catatan mengenai toFixed: perhatikan bahwa meningkatkan presisi dapat menghasilkan hasil yang tidak terduga:, (1.2).toFixed(16) === "1.2000000000000000"sementara (1.2).toFixed(17) === "1.19999999999999996"(di Firefox / Chrome; di IE8 yang terakhir tidak berlaku karena presisi yang lebih rendah yang ditawarkan IE8 secara internal).
jakub.g
2
Harap dicatat bahwa bahkan (0.598).toFixed(2)tidak menghasilkan 0.6. Ini menghasilkan 0.60:)
qbolec
1
Juga, berhati-hatilah dari pembulatan inconstistent: (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2).
Skippy le Grand Gourou
36

Satu lagi masalah yang harus diperhatikan, adalah yang toFixed()dapat menghasilkan nol yang tidak perlu di akhir angka. Sebagai contoh:

var x=(23-7.37)
x
15.629999999999999
x.toFixed(6)
"15.630000"

Idenya adalah untuk membersihkan output menggunakan RegExp:

function humanize(x){
  return x.toFixed(6).replace(/\.?0*$/,'');
}

Yang RegExpcocok dengan trailing nol (dan opsional titik desimal) untuk memastikan itu terlihat bagus untuk bilangan bulat juga.

humanize(23-7.37)
"15.63"
humanize(1200)
"1200"
humanize(1200.03)
"1200.03"
humanize(3/4)
"0.75"
humanize(4/3)
"1.333333"
qbolec
sumber
Number.prototype.minFixed = fungsi (desimal) {kembalikan this.toFixed (desimal). Ganti (/ \.? 0 * $ /, ""); }
Luc Bloom
Ini harus diterima, membuntuti nol mengganggu, saya sedang mencari solusi ini, gj.
exoslav
1
Mengejar nol mungkin menyebalkan, tapi inilah yang persisnya dijanjikan oleh nama metode "toFixed;)
ksadowski
11
var x = 0.3445434
x = Math.round (x*100) / 100 // this will make nice rounding
Ilya Birman
sumber
Math.round (1,015 * 100) / 100 memberi 1,01 sementara kita mengharapkannya menjadi 1,02?
gaurav5430
6

Ada masalah dengan semua solusi yang beredar menggunakan pengganda. Sayangnya, solusi kkyy dan Christoph salah.

Silakan uji kode Anda untuk nomor 551.175 dengan 2 tempat desimal - itu akan membulatkan ke 551.17 sementara itu harus 551.18 ! Tetapi jika Anda menguji mantan. 451.175 itu akan baik-baik saja - 451.18. Jadi sulit untuk menemukan kesalahan ini pada pandangan pertama.

Masalahnya adalah dengan mengalikan: coba 551.175 * 100 = 55117.49999999999 (ups!)

Jadi ide saya adalah memperlakukannya dengan toFixed () sebelum menggunakan Math.round ();

function roundFix(number, precision)
{
    var multi = Math.pow(10, precision);
    return Math.round( (number * multi).toFixed(precision + 1) ) / multi;
}
ArteQ
sumber
1
Itulah masalah dengan aritmatika dalam js: (551.175 * 10 * 10)! == (551.175 * 100). Anda harus menggunakan kenaikan desimal untuk memindahkan koma untuk hasil desimal yang tidak nyata.
Kir Kanos
+1 untuk memperhatikan hal ini, namun toFixedterpengaruh juga - (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)... Metode apa pun yang digunakan, lebih baik tambahkan epsilon sebelum pembulatan.
Skippy le Grand Gourou
5

Kuncinya di sini saya kira adalah untuk mengumpulkan dengan benar terlebih dahulu, maka Anda dapat mengubahnya menjadi String.

function roundOf(n, p) {
    const n1 = n * Math.pow(10, p + 1);
    const n2 = Math.floor(n1 / 10);
    if (n1 >= (n2 * 10 + 5)) {
        return (n2 + 1) / Math.pow(10, p);
    }
    return n2 / Math.pow(10, p);
}

// All edge cases listed in this thread
roundOf(95.345, 2); // 95.35
roundOf(95.344, 2); // 95.34
roundOf(5.0364342423, 2); // 5.04
roundOf(0.595, 2); // 0.60
roundOf(0.335, 2); // 0.34
roundOf(0.345, 2); // 0.35
roundOf(551.175, 2); // 551.18
roundOf(0.3445434, 2); // 0.34

Sekarang Anda dapat dengan aman memformat nilai ini dengan toFixed (p). Jadi dengan kasus spesifik Anda:

roundOf(0.3445434, 2).toFixed(2); // 0.34
Steven
sumber
3

Jika Anda menginginkan string tanpa putaran, Anda dapat menggunakan RegEx ini (mungkin bukan cara yang paling efisien ... tetapi sangat mudah)

(2.34567778).toString().match(/\d+\.\d{2}/)[0]
// '2.34'
Pablo Andres Diaz Mazzaro
sumber
1
function trimNumber(num, len) {
  const modulu_one = 1;
  const start_numbers_float=2;
  var int_part = Math.trunc(num);
  var float_part = String(num % modulu_one);
      float_part = float_part.slice(start_numbers_float, start_numbers_float+len);
  return int_part+'.'+float_part;
}
ofir_aghai
sumber
jawaban yang bagus kecuali bahwa Anda kehilangan titik koma (Tidak, di es6 titik koma tidak usang dan kami masih harus menggunakannya dalam beberapa kasus). Aku harus juga mengedit baris terakhir ke: return float_part ? int_part+'.'+float_part : int_part;sebaliknya jika Anda melewati Integer, itu kembali nomor dengan titik di akhir (contoh masukan: 2100, keluaran: 2100.)
Kuba Simonovsky
0

Mungkin Anda juga ingin pemisah desimal? Ini adalah fungsi yang baru saja saya buat:

function formatFloat(num,casasDec,sepDecimal,sepMilhar) {
    if (num < 0)
    {
        num = -num;
        sinal = -1;
    } else
        sinal = 1;
    var resposta = "";
    var part = "";
    if (num != Math.floor(num)) // decimal values present
    {
        part = Math.round((num-Math.floor(num))*Math.pow(10,casasDec)).toString(); // transforms decimal part into integer (rounded)
        while (part.length < casasDec)
            part = '0'+part;
        if (casasDec > 0)
        {
            resposta = sepDecimal+part;
            num = Math.floor(num);
        } else
            num = Math.round(num);
    } // end of decimal part
    while (num > 0) // integer part
    {
        part = (num - Math.floor(num/1000)*1000).toString(); // part = three less significant digits
        num = Math.floor(num/1000);
        if (num > 0)
            while (part.length < 3) // 123.023.123  if sepMilhar = '.'
                part = '0'+part; // 023
        resposta = part+resposta;
        if (num > 0)
            resposta = sepMilhar+resposta;
    }
    if (sinal < 0)
        resposta = '-'+resposta;
    return resposta;
}
Rodrigo
sumber
0

Tidak ada cara untuk menghindari pembulatan yang tidak konsisten untuk harga dengan x.xx5 sebagai nilai aktual menggunakan perkalian atau pembagian. Jika Anda perlu menghitung harga yang benar di sisi klien, Anda harus menyimpan semua jumlah sen. Ini karena sifat representasi internal dari nilai numerik dalam JavaScript. Perhatikan bahwa Excel menderita masalah yang sama sehingga kebanyakan orang tidak akan melihat kesalahan kecil yang disebabkan oleh fenomena ini. Namun kesalahan dapat menumpuk setiap kali Anda menambahkan banyak nilai yang dihitung, ada teori keseluruhan tentang ini yang melibatkan urutan perhitungan dan metode lain untuk meminimalkan kesalahan dalam hasil akhir. Untuk menekankan pada masalah dengan nilai desimal, harap dicatat bahwa 0,1 + 0,2 tidak persis sama dengan 0,3 dalam JavaScript, sedangkan 1 + 2 sama dengan 3.

Dony
sumber
solusinya adalah dengan memisahkan seluruh bagian dan bagian desimal, dan mewakili mereka sebagai bilangan bulat di basis 10, daripada menggunakan pelampung, di sini ia bekerja tanpa masalah untuk prettyPrint, tetapi secara umum Anda harus memilih antara basis dan yang lain, representasi untuk bilangan real dan lainnya, masing-masing memiliki masalah
menyatukan
"Excel menderita masalah yang sama". sumber?
gaurav5430
0
/** don't spend 5 minutes, use my code **/
function prettyFloat(x,nbDec) { 
    if (!nbDec) nbDec = 100;
    var a = Math.abs(x);
    var e = Math.floor(a);
    var d = Math.round((a-e)*nbDec); if (d == nbDec) { d=0; e++; }
    var signStr = (x<0) ? "-" : " ";
    var decStr = d.toString(); var tmp = 10; while(tmp<nbDec && d*tmp < nbDec) {decStr = "0"+decStr; tmp*=10;}
    var eStr = e.toString();
    return signStr+eStr+"."+decStr;
}

prettyFloat(0);      //  "0.00"
prettyFloat(-1);     // "-1.00"
prettyFloat(-0.999); // "-1.00"
prettyFloat(0.5);    //  "0.50"
reun
sumber
0

Saya menggunakan kode ini untuk memformat pelampung. Ini didasarkan pada toPrecision()tetapi strip nol yang tidak perlu. Saya akan menyambut saran untuk bagaimana menyederhanakan regex.

function round(x, n) {
    var exp = Math.pow(10, n);
    return Math.floor(x*exp + 0.5)/exp;
}

Contoh penggunaan:

function test(x, n, d) {
    var rounded = rnd(x, d);
    var result = rounded.toPrecision(n);
    result = result.replace(/\.?0*$/, '');
    result = result.replace(/\.?0*e/, 'e');
    result = result.replace('e+', 'e');
    return result;  
}

document.write(test(1.2000e45, 3, 2) + '=' + '1.2e45' + '<br>');
document.write(test(1.2000e+45, 3, 2) + '=' + '1.2e45' + '<br>');
document.write(test(1.2340e45, 3, 2) + '=' + '1.23e45' + '<br>');
document.write(test(1.2350e45, 3, 2) + '=' + '1.24e45' + '<br>');
document.write(test(1.0000, 3, 2) + '=' + '1' + '<br>');
document.write(test(1.0100, 3, 2) + '=' + '1.01' + '<br>');
document.write(test(1.2340, 4, 2) + '=' + '1.23' + '<br>');
document.write(test(1.2350, 4, 2) + '=' + '1.24' + '<br>');
Menandai
sumber