Javascript: memformat bilangan bulat menjadi N desimal

104

di JavaScript, cara umum untuk membulatkan angka ke N tempat desimal adalah seperti:

function roundNumber(num, dec) {
  return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
}

Namun pendekatan ini akan membulatkan ke maksimum N tempat desimal sementara saya ingin selalu membulatkan ke N tempat desimal. Misalnya "2.0" akan dibulatkan menjadi "2".

Ada ide?

hoju
sumber
9
biasanya, Anda dapat menggunakan toFixed()( developer.mozilla.org/En/Core_JavaScript_1.5_Reference/… ), tetapi bermasalah di IE: stackoverflow.com/questions/661562/… ; Anda harus menulis versi Anda sendiri ...
Christoph
1
@ Hoju - mungkin mengubah jawaban yang diterima - Jawaban David benar untuk IE8 +, sedangkan jawaban yang diterima memiliki beberapa bug serius di semua browser.
robocat
@robocat: Apakah Anda serius?
Guffa

Jawaban:

25

Itu bukan masalah pembulatan, itu masalah tampilan. Angka tidak berisi informasi tentang digit signifikan; nilai 2 sama dengan 2.0000000000000. Saat Anda mengubah nilai yang dibulatkan menjadi string, Anda membuatnya menampilkan sejumlah digit.

Anda bisa menambahkan angka nol setelah nomor tersebut, seperti:

var s = number.toString();
if (s.indexOf('.') == -1) s += '.';
while (s.length < s.indexOf('.') + 4) s += '0';

(Perhatikan bahwa ini mengasumsikan bahwa pengaturan kawasan klien menggunakan titik sebagai pemisah desimal, kode memerlukan lebih banyak pekerjaan untuk berfungsi untuk pengaturan lain.)

Guffa
sumber
3
toFixed bermasalah..misalnya desimal: 1.02449999998 jika Anda melakukan dec.toFixed (4) => 1.0244. Seharusnya 1,0245 sebagai gantinya.
Bat_Programmer
2
@deepeshk Tapi apa masalah jika menggunakan toFixed()desimal di akhir, setelah pembulatan?
pauloya
10
@deepeshk di browser apa? Baru saja mencobanya di Chrome 17 dan 1.02449999998.toFixed(4)kembali dengan benar 1.0245.
Matt Ball
3
@ MarkTomlin: Maka tampaknya Anda memiliki string, bukan angka.
Guffa
1
.toFixed () bekerja dengan sangat baik di browser modern (Saya menguji Chrome, Firefox, IE11, IE8). @Bat_Programmer - harap jelaskan browser mana yang menurut Anda memiliki bug itu.
robocat
243

Saya pikir ada pendekatan yang lebih sederhana untuk semua yang diberikan di sini, dan metodenya Number.toFixed()sudah diterapkan dalam JavaScript.

cukup tulis:

var myNumber = 2;

myNumber.toFixed(2); //returns "2.00"
myNumber.toFixed(1); //returns "2.0"

dll ...

David
sumber
Dimana disebutkan, hoju? Saya meninjau jawaban lain dan saya tidak menemukan siapa pun yang melaporkan bahwa fungsi toFixed bermasalah. Terima kasih
David
@David: Itu disebutkan dalam komentar untuk jawaban, misalnya.
Guffa
13
PERHATIAN: toFixed()mengembalikan string.
Jordan Arseno
2
@JordanArseno ini bisa diperbaiki menggunakan parseInt (myNumber.toFixed (intVar)); untuk mengembalikan nilai integer, atau parseFloat (myNumber.toFixed (floatVar)); untuk mengembalikan float jika pengguna memiliki tempat desimal.
Stephen Romero
50

Saya menemukan cara. Ini adalah kode Christoph dengan perbaikan:

function toFixed(value, precision) {
    var precision = precision || 0,
        power = Math.pow(10, precision),
        absValue = Math.abs(Math.round(value * power)),
        result = (value < 0 ? '-' : '') + String(Math.floor(absValue / power));

    if (precision > 0) {
        var fraction = String(absValue % power),
            padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');
        result += '.' + padding + fraction;
    }
    return result;
}

Baca detail pengulangan karakter menggunakan konstruktor array di sini jika Anda penasaran mengapa saya menambahkan "+ 1".

Elias Zamaria
sumber
Meneruskan nilai 708.3333333333333 dengan presisi 2 atau 3 menghasilkan nilai kembali 708,00 untuk saya. Saya membutuhkan ini untuk 2 tempat desimal, di Chrome dan IE 9 .toFixed (2) memenuhi kebutuhan saya.
alan
ini bukan cara yang umum, misalnya, toFixed (16.775, 2) menghasilkan 16.77. Ubah angka menjadi String lalu ubah adalah satu-satunya cara.
hiway
2
Ada bug dengan metode ini: toFixed (-0.1111, 2) mengembalikan 0.11, yaitu tanda negatif hilang.
Matt
Bekerja dengan baik, kecuali untuk itu saya telah menambahkan parseFloat (hasil) di akhir. Layak diedit.
Artur Barseghyan
16

Selalu ada cara yang lebih baik untuk melakukan sesuatu.

var number = 51.93999999999761;

Saya ingin mendapatkan presisi empat digit: 51,94

kerjakan saja:

number.toPrecision(4);

hasilnya akan jadi: 51.94

de.la.ru
sumber
2
Dan bagaimana jika Anda menambahkan 100? Apakah Anda perlu mengubahnya menjadi number.toPrecision (5)?
JohnnyBizzle
2
Iya. 31.939383.toPrecision (4)> "31.94" / 131.939383.toPrecision (4)> "131.9"
ReSpawN
6

Metode pembulatan seperti PHP

Kode di bawah ini dapat digunakan untuk menambahkan versi Math.round Anda sendiri ke namespace Anda yang menggunakan parameter presisi. Tidak seperti pembulatan Desimal pada contoh di atas, ini tidak melakukan konversi ke dan dari string, dan parameter presisi bekerja dengan cara yang sama seperti PHP dan Excel di mana 1 positif akan dibulatkan ke 1 tempat desimal dan -1 akan dibulatkan ke puluhan.

var myNamespace = {};
myNamespace.round = function(number, precision) {
    var factor = Math.pow(10, precision);
    var tempNumber = number * factor;
    var roundedTempNumber = Math.round(tempNumber);
    return roundedTempNumber / factor;
};

myNamespace.round(1234.5678, 1); // 1234.6
myNamespace.round(1234.5678, -1); // 1230

dari referensi Pengembang Mozilla untuk Math.round ()

JohnnyBizzle
sumber
2

Semoga kode berfungsi (tidak melakukan banyak pengujian):

function toFixed(value, precision) {
    var precision = precision || 0,
        neg = value < 0,
        power = Math.pow(10, precision),
        value = Math.round(value * power),
        integral = String((neg ? Math.ceil : Math.floor)(value / power)),
        fraction = String((neg ? -value : value) % power),
        padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');

    return precision ? integral + '.' +  padding + fraction : integral;
}
Christoph
sumber
Kode Anda memiliki bug. Saya mencoba toFixed (2.01, 4) dan mendapatkan hasil "2.100". Jika saya menemukan cara untuk memperbaikinya, saya akan mempostingnya sebagai jawaban untuk pertanyaan ini.
Elias Zamaria
@ mikez302: komputasi padding dimatikan satu per satu; seharusnya bekerja sekarang, tapi jangan ragu untuk menggangguku lagi jika masih rusak ...
Christoph
Sangat aneh. Ketika saya menjalankan fungsi ini dengan konsol firebug terbuka di firefox 17 itu membekukan seluruh browser seperti js terjebak dalam loop tanpa akhir. Bahkan jika saya tidak konsol.log output. Jika saya tidak mengaktifkan firebug, bug tidak terjadi.
SublymeRick
1
Perbarui, saya menjalankannya di chrome dan saya mendapatkan: Uncaught RangeError: Ukuran tumpukan panggilan maksimum terlampaui sehubungan dengan panggilan fungsi toFixed.
SublymeRick
@SublymeRick: Saya tidak tahu mengapa ini terjadi; ditembak dalam gelap: coba ganti nama fungsinya ...
Christoph
2

Saya pikir fungsi di bawah ini dapat membantu

function roundOff(value,round) {
   return (parseInt(value * (10 ** (round + 1))) - parseInt(value * (10 ** round)) * 10) > 4 ? (((parseFloat(parseInt((value + parseFloat(1 / (10 ** round))) * (10 ** round))))) / (10 ** round)) : (parseFloat(parseInt(value * (10 ** round))) / ( 10 ** round));
}

penggunaan: roundOff(600.23458,2);akan kembali600.23

KRISHNA TEJA
sumber
2

Ini berfungsi untuk membulatkan ke angka N (jika Anda hanya ingin memotong ke angka N, hapus panggilan Math.round dan gunakan yang Math.trunc):

function roundN(value, digits) {
   var tenToN = 10 ** digits;
   return /*Math.trunc*/(Math.round(value * tenToN)) / tenToN;
}

Harus menggunakan logika seperti itu di Jawa di masa lalu ketika saya membuat manipulasi data komponen E-Slate . Itu karena saya telah menemukan bahwa menambahkan 0,1 kali ke 0 Anda akan berakhir dengan beberapa bagian desimal panjang yang tidak terduga (ini karena aritmatika floating point).

Komentar pengguna di Format nomor untuk selalu menampilkan 2 tempat desimal memanggil penskalaan teknik ini.

Beberapa menyebutkan ada kasus yang tidak bulat seperti yang diharapkan dan di http://www.jacklmoore.com/notes/rounding-in-javascript/ ini disarankan:

function round(value, decimals) {
  return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}
George Birbilis
sumber
btw, POSITS menjanjikan untuk arsitektur h / w masa depan: nextplatform.com/2019/07/08/…
George Birbilis
-2

Jika Anda tidak terlalu peduli tentang pembulatan, tambahkan saja toFixed (x) dan kemudian hapus tanda 0es dan titik jika perlu. Ini bukanlah solusi yang cepat.

function format(value, decimals) {
    if (value) {
        value = value.toFixed(decimals);            
    } else {
        value = "0";
    }
    if (value.indexOf(".") < 0) { value += "."; }
    var dotIdx = value.indexOf(".");
    while (value.length - dotIdx <= decimals) { value += "0"; } // add 0's

    return value;
}
Juan Carrey
sumber
Saya mencoba format(1.2, 5)dan mendapatkan 1.2, seperti yang saya harapkan 1.20000.
Elias Zamaria
Maaf @EliasZamaria, awalnya tidak mengerti. Saya telah mengedit postingan. Perhatikan bahwa itu akan mengembalikan "0,0000" ketika nilainya tidak ditentukan.
Juan Carrey