Javascript: การจัดรูปแบบตัวเลขที่ปัดเศษเป็น N ทศนิยม


104

ใน JavaScript วิธีทั่วไปในการปัดเศษตัวเลขเป็น N ตำแหน่งทศนิยมมีดังนี้:

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

อย่างไรก็ตามวิธีการนี้จะรอบไปสูงสุดของ N ตำแหน่งทศนิยมในขณะที่ฉันต้องการที่จะเสมอรอบ N ตำแหน่งทศนิยม ตัวอย่างเช่น "2.0" จะถูกปัดเศษเป็น "2"

ความคิดใด ๆ ?


9
โดยปกติคุณสามารถใช้toFixed()( developer.mozilla.org/En/Core_JavaScript_1.5_Reference/… ) แต่บั๊กใน IE: stackoverflow.com/questions/661562/… ; คุณจะต้องเขียนเวอร์ชันของคุณเอง ...
Christoph

1
@hoju - อาจมีการเปลี่ยนแปลงคำตอบที่ยอมรับ - คำตอบของ David นั้นถูกต้องสำหรับ IE8 + ในขณะที่คำตอบที่ยอมรับนั้นมีข้อบกพร่องร้ายแรงบางอย่างในเบราว์เซอร์ทั้งหมด
robocat

@robocat: ซีเรียสมั้ย?
Guffa

คำตอบ:


25

นั่นไม่ใช่ปัญหาการปัดเศษนั่นคือปัญหาการแสดงผล ตัวเลขไม่มีข้อมูลเกี่ยวกับเลขนัยสำคัญ ค่า 2 เหมือนกับ 2.0000000000000 เมื่อคุณเปลี่ยนค่าที่ปัดเศษเป็นสตริงที่คุณกำหนดให้แสดงตัวเลขจำนวนหนึ่ง

คุณสามารถเพิ่มศูนย์หลังตัวเลขได้เช่น:

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

(โปรดทราบว่าสิ่งนี้จะถือว่าการตั้งค่าภูมิภาคของไคลเอนต์ใช้จุดเป็นตัวคั่นทศนิยมรหัสต้องทำงานเพิ่มเติมเพื่อทำงานสำหรับการตั้งค่าอื่น ๆ )


3
toFixed คือ buggy .. ตัวอย่างเช่นทศนิยม: 1.02449999998 ถ้าคุณทำ dec.toFixed (4) => 1.0244 ควรเป็น 1.0245 แทน
Bat_Programmer

2
@deepeshk แต่จะมีปัญหาอะไรกับการใช้ฐานtoFixed()รองทศนิยมในตอนท้ายหลังจากปัดเศษ?
pauloya

10
@deepeshk ในเบราว์เซอร์อะไร เพียงแค่พยายามมันใน Chrome 17 และถูกต้องผลตอบแทน1.02449999998.toFixed(4) 1.0245
Matt Ball

3
@MarkTomlin: ดูเหมือนว่าคุณจะมีสตริงแทนตัวเลข
Guffa

1
.toFixed () ทำงานได้อย่างยอดเยี่ยมในเบราว์เซอร์สมัยใหม่ (ฉันทดสอบ Chrome, Firefox, IE11, IE8) @Bat_Programmer - โปรดชี้แจงว่าเบราว์เซอร์ใดที่คุณคิดว่ามีข้อบกพร่องนั้น
robocat

244

ฉันคิดว่ามีวิธีที่ง่ายกว่าสำหรับทั้งหมดที่ระบุไว้ที่นี่และเป็นวิธีการที่Number.toFixed()ใช้งานใน JavaScript แล้ว

เพียงแค่เขียน:

var myNumber = 2;

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

ฯลฯ ...


ที่กล่าวถึงโฮจู? ฉันตรวจสอบคำตอบอื่น ๆ และไม่พบว่ามีใครรายงานว่าฟังก์ชัน toFixed นั้นมีปัญหา ขอบคุณ
เดวิด

@ เดวิด: ที่กล่าวถึงในความคิดเห็นของคำตอบเช่น
Guffa

13
ข้อควรระวัง: toFixed()ส่งคืนสตริง
Jordan Arseno

2
@JordanArseno สิ่งนี้สามารถแก้ไขได้โดยใช้ parseInt (myNumber.toFixed (intVar)); เพื่อส่งคืนค่าจำนวนเต็มหรือ parseFloat (myNumber.toFixed (floatVar)); เพื่อส่งคืนค่าลอยหากผู้ใช้มีตำแหน่งทศนิยม
Stephen Romero

50

ฉันพบวิธีแล้ว นี่คือรหัสของ Christoph พร้อมการแก้ไข:

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;
}

อ่านรายละเอียดของการทำซ้ำอักขระโดยใช้ตัวสร้างอาร์เรย์ที่นี่หากคุณสงสัยว่าทำไมฉันจึงเพิ่ม "+ 1"


การส่งผ่านค่า 708.3333333333333 ด้วยความแม่นยำ 2 หรือ 3 ผลลัพธ์ในค่าส่งกลับ 708.00 สำหรับฉัน ฉันต้องการสิ่งนี้สำหรับทศนิยม 2 ตำแหน่งใน Chrome และ IE 9 .toFixed (2) ตรงตามความต้องการของฉัน
อลัน

นี่ไม่ใช่วิธีทั่วไปเช่น toFixed (16.775, 2) ส่งคืน 16.77 แปลงตัวเลขเป็น String จากนั้นแปลงเป็นวิธีเดียว
hiway

2
มีจุดบกพร่องด้วยวิธีนี้: toFixed (-0.1111, 2) ส่งคืน 0.11 นั่นคือเครื่องหมายลบหายไป
Matt

ใช้งานได้ดียกเว้นว่าฉันได้เพิ่ม parseFloat (ผลลัพธ์) ในตอนท้าย ควรค่าแก่การแก้ไข
Artur Barseghyan

16

มีวิธีที่ดีกว่าในการทำสิ่งต่างๆเสมอ

var number = 51.93999999999761;

ฉันต้องการความแม่นยำสี่หลัก: 51.94

แค่ทำ:

number.toPrecision(4);

ผลลัพธ์จะเป็น: 51.94


2
แล้วถ้าบวก 100 ล่ะ? คุณต้องเปลี่ยนเป็น number.toPrecision (5) หรือไม่?
JohnnyBizzle

2
ใช่. 31.939383.toPrecision (4)> "31.94" / 131.939383.toPrecision (4)> "131.9"
ReSpawN

6

วิธีการปัดเศษ PHP-Like

คุณสามารถใช้โค้ดด้านล่างเพื่อเพิ่ม Math.round เวอร์ชันของคุณเองลงในเนมสเปซของคุณเองซึ่งใช้พารามิเตอร์ที่แม่นยำ ซึ่งแตกต่างจากการปัดเศษทศนิยมในตัวอย่างข้างต้นซึ่งจะไม่มีการแปลงเป็นและจากสตริงและพารามิเตอร์ความแม่นยำจะทำงานในลักษณะเดียวกับ PHP และ Excel โดยค่าบวก 1 จะปัดเศษเป็นทศนิยม 1 ตำแหน่งและ -1 จะปัดเศษเป็นหลัก

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

จากMozilla Developer reference สำหรับ Math.round ()


2

หวังว่าโค้ดจะใช้งานได้ (ไม่ได้ทำการทดสอบมากนัก):

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;
}

รหัสของคุณมีจุดบกพร่อง ฉันพยายามแก้ไข (2.01, 4) และได้ผลลัพธ์เป็น "2.100" ถ้าฉันเคยหาวิธีแก้ไขได้ฉันจะโพสต์เป็นคำตอบสำหรับคำถามนี้
Elias Zamaria

@ mikez302: การคำนวณช่องว่างภายในถูกปิดโดยหนึ่ง; ควรใช้งานได้แล้ว แต่อย่าลังเลที่จะรบกวนฉันอีกครั้งถ้ามันยังพัง ...
Christoph

ที่แปลกมาก. เมื่อฉันเรียกใช้ fuction นี้โดยเปิดคอนโซล firebug ใน firefox 17 มันจะค้างทั้งเบราว์เซอร์เช่น js ติดอยู่ในวงวนไม่รู้จบ แม้ว่าฉันจะไม่ได้ console.log เอาต์พุต หากฉันไม่ได้เปิดใช้งาน firebug ข้อผิดพลาดจะไม่เกิดขึ้น
SublymeRick

1
อัปเดตฉันรันใน chrome และฉันได้รับ: Uncaught RangeError: ขนาดสแต็กการโทรสูงสุดเกินในส่วนที่เกี่ยวข้องกับการเรียกฟังก์ชัน toFixed
SublymeRick

@SublymeRick: ฉันไม่รู้ว่าทำไมสิ่งนี้ถึงเกิดขึ้น; shot in the dark: ลองเปลี่ยนชื่อฟังก์ชั่น ...
Christoph

2

ฉันคิดว่าฟังก์ชันด้านล่างสามารถช่วยได้

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));
}

การใช้งาน: roundOff(600.23458,2);จะกลับมา600.23


2

วิธีนี้ใช้ได้กับการปัดเศษเป็น N หลัก (หากคุณต้องการตัดทอนเป็น N หลักให้ลบการเรียก Math.round และใช้ Math.trunc หนึ่งหลัก):

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

มีรีสอร์ทให้ตรรกะดังกล่าวใน Java ในอดีตที่ผ่านมาเมื่อผมเขียนจัดการข้อมูลส่วนประกอบ E-Slate นั่นคือเนื่องจากฉันได้พบว่าการเพิ่ม 0.1 หลาย ๆ ครั้งเป็น 0 คุณจะได้ส่วนทศนิยมที่ยาวโดยไม่คาดคิด (นี่เป็นเพราะเลขคณิตลอยตัว)

ความคิดเห็นของผู้ใช้ที่Format number เพื่อแสดงทศนิยม 2 ตำแหน่งเสมอเรียกเทคนิคนี้ว่า scaling

บางคนพูดถึงมีบางกรณีที่ไม่ได้รอบตามที่คาดไว้และที่http://www.jacklmoore.com/notes/rounding-in-javascript/สิ่งนี้แนะนำแทน:

function round(value, decimals) {
  return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}

btw, POSITS มีแนวโน้มสำหรับสถาปัตยกรรม h / w ในอนาคต: nextplatform.com/2019/07/08/…
George Birbilis

-2

หากคุณไม่สนใจเรื่องการปัดเศษเพียงแค่เพิ่ม toFixed (x) จากนั้นลบ 0es และจุดต่อท้ายหากจำเป็น ไม่ใช่วิธีการแก้ปัญหาที่รวดเร็ว

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;
}

ฉันพยายามformat(1.2, 5)และได้รับในขณะที่ผมคาดว่า1.2 1.20000
Elias Zamaria

ขอโทษ @EliasZamaria ตอนแรกไม่เข้าใจ ฉันได้แก้ไขโพสต์แล้ว โปรดทราบว่าจะส่งคืน "0.0000" เมื่อไม่ได้กำหนดค่า
Juan Carrey
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.