วิธีการจัดรูปแบบลอยในจาวาสคริปต์ได้อย่างไร


427

ใน JavaScript เมื่อแปลงจากทศนิยมเป็นสตริงฉันจะได้รับเพียง 2 หลักหลังจุดทศนิยมได้อย่างไร ตัวอย่างเช่น 0.34 แทน 0.3445434


16
เพียงแค่หยิบขึ้นมานิดหน่อย: คุณต้องการ 'ตัดออก' ทั้งหมดยกเว้นตัวเลขสองตัวแรกหรือคุณต้องการปัดเศษเป็นตัวเลขสองหลัก?
xtofl

คำตอบ:


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

ข้อมูลเฉพาะในกรณีที่รหัสไม่สามารถอธิบายตนเองได้

แก้ไข: ... หรือเพียงแค่ใช้toFixedตามที่เสนอโดยทิม Buthe ลืมสิ่งนั้นขอบคุณสำหรับการเตือน (และ upvote) :)


1
ฉันใช้สิ่งนี้ในห้องสมุด "Highchart" ซึ่งไม่ยอมรับค่าสตริงดังนั้นการแก้ไขไม่ทำงานสำหรับฉัน Math.round แก้ไขปัญหาของฉันขอบคุณ
Swapnil Chincholkar

4
toFixed()จะเลียนแบบสิ่งที่ชอบprintf()ทำใน C อย่างไรก็ตามtoFixed()และMath.round()จะจัดการการปัดเศษที่แตกต่างกัน ในกรณีนี้toFixed()จะมีเอฟเฟกต์แบบเดียวกันMath.floor()(ให้คุณคูณต้นฉบับด้วย 10 ^ n ล่วงหน้าและโทรtoFixed()ด้วยตัวเลข n) "ความถูกต้อง" ของคำตอบนั้นขึ้นอยู่กับสิ่งที่ OP ต้องการที่นี่และทั้งสองอย่าง "ถูกต้อง" ในแบบของพวกเขาเอง
DDPWNAGE

838

มีฟังก์ชั่นเพื่อปัดเศษตัวเลข ตัวอย่างเช่น:

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

จะพิมพ์ 5.04

แก้ไข: ซอ


7
ผมอยากจะแนะนำต่อโดยใช้การพิมพ์ () ในเบราว์เซอร์แม้ว่า
cobbal

70
ระวังเกี่ยวกับเรื่องนี้ toFixed () จะคืนค่าสตริง: var x = 5.036432346; var y = x.toFixed(2) + 100; yจะเท่ากับ"5.03100"
Vlad

5
โปรดทราบว่า (1e100) .toFixed (2) === "1e + 100"
qbolec

7
นอกจากนี้ระวังการปัดเศษที่ไม่สอดคล้องกัน: (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)
Skippy le Grand Gourou

3
หากคุณค้นหาสิ่งที่เทียบเท่ากับการแก้ไข แต่ด้วยการปัดเศษที่สอดคล้องกันให้ใช้ toLocaleString: (0.345) .toLocaleString ('en-EN', {ลดขั้นต่ำสุดส่วนที่คั่น: 2, ค่าสูงสุดเศษส่วน: 2})
fred727

185

ระวังเมื่อใช้toFixed():

ขั้นแรกให้การปัดเศษตัวเลขทำได้โดยใช้การแทนเลขฐานสองของตัวเลขซึ่งอาจนำไปสู่พฤติกรรมที่ไม่คาดคิด ตัวอย่างเช่น

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

'0.6'แทน

ประการที่สองมีข้อผิดพลาด IE toFixed()กับ ใน IE (อย่างน้อยถึงเวอร์ชัน 7 ไม่ได้ตรวจสอบ IE8) สิ่งต่อไปนี้ถือเป็นจริง:

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

มันอาจเป็นความคิดที่ดีที่จะทำตามคำแนะนำของ kkyy หรือใช้toFixed()ฟังก์ชั่นที่กำหนดเองเช่น

function toFixed(value, precision) {
    var power = Math.pow(10, precision || 0);
    return String(Math.round(value * power) / power);
}

ใช่สิ่งนี้สำคัญมากเมื่อสร้างรหัสเพื่อทำนายราคา ขอบคุณ! +1
Fabio Milheiro

10
ฉันขอแนะนำให้เพิ่ม.toFixed()วิธีการเนทีฟในค่าส่งคืนซึ่งจะเพิ่มจำนวนความแม่นยำที่ต้องการเช่น: return (Math.round(value * power) / power).toFixed(precision);และส่งคืนค่าเป็นสตริง มิฉะนั้นความแม่นยำของ 20 จะถูกละเว้นสำหรับทศนิยมขนาดเล็ก
William Joss Crowcroft

3
หมายเหตุหนึ่งเกี่ยวกับtoFixed: โปรดทราบว่าการเพิ่มความแม่นยำสามารถให้ผลลัพธ์ที่ไม่คาดคิด: (1.2).toFixed(16) === "1.2000000000000000"ในขณะที่(1.2).toFixed(17) === "1.19999999999999996"(ใน Firefox / Chrome; ใน IE8 ส่วนหลังไม่ถือเนื่องจากความแม่นยำต่ำกว่าที่ IE8 สามารถเสนอให้ภายในได้)
jakub.g

2
โปรดทราบว่าแม้ไม่ได้ผลิต(0.598).toFixed(2) 0.6มันสร้าง0.60:)
qbolec

1
นอกจากนี้ระวังของการปัดเศษ (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)inconstistent:
Skippy le Grand Gourou

36

อีกปัญหาที่ต้องระวังคือtoFixed()สามารถสร้างศูนย์ที่ไม่จำเป็นในตอนท้ายของจำนวน ตัวอย่างเช่น:

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

แนวคิดคือการล้างเอาต์พุตโดยใช้RegExp:

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

RegExpตรงกับศูนย์ต่อท้าย (และเลือกจุดทศนิยม) เพื่อให้แน่ใจว่ามันดูดีสำหรับจำนวนเต็มเช่นกัน

humanize(23-7.37)
"15.63"
humanize(1200)
"1200"
humanize(1200.03)
"1200.03"
humanize(3/4)
"0.75"
humanize(4/3)
"1.333333"

Number.prototype.minFixed = function (ทศนิยม) {return this.toFixed (ทศนิยม) .replace (/ \.? 0 * $ /, ""); }
Luc Bloom

นี่ควรจะเป็น acepted เลขศูนย์ต่อท้ายเป็นที่น่ารำคาญ
exoslav

1
ศูนย์ต่อท้ายอาจจะน่ารำคาญ แต่นี่คือสิ่งที่ชื่อวิธีการ "toFixed" สัญญาว่าจะทำ;)
358

11
var x = 0.3445434
x = Math.round (x*100) / 100 // this will make nice rounding

Math.round (1.015 * 100) / 100 ให้ 1.01 ในขณะที่เราคาดหวังว่าจะเป็น 1.02?
gaurav5430

6

มีปัญหากับการแก้ปัญหาทั้งหมดที่ลอยอยู่รอบ ๆ โดยใช้ตัวคูณ วิธีแก้ปัญหาทั้งของ kkyy และ Christoph นั้นผิดพลาดอย่างน่าเสียดาย

โปรดทดสอบรหัสของคุณสำหรับหมายเลข551.175ด้วยทศนิยม 2 ตำแหน่งโดยจะปัดเป็น551.17ในขณะที่ควรเป็น551.18 ! แต่ถ้าคุณทดสอบเช่น 451.175 มันก็โอเค - 451.18 ดังนั้นจึงเป็นการยากที่จะสังเกตเห็นข้อผิดพลาดนี้ได้อย่างรวดเร็วในครั้งแรก

ปัญหาเกิดขึ้นจากการคูณ: ลอง 551.175 * 100 = 55117.49999999999 (อัพ!)

ดังนั้นความคิดของฉันคือปฏิบัติต่อ toFixed () ก่อนใช้ Math.round ();

function roundFix(number, precision)
{
    var multi = Math.pow(10, precision);
    return Math.round( (number * multi).toFixed(precision + 1) ) / multi;
}

1
นั่นเป็นปัญหาของเลขคณิตใน js: (551.175 * 10 * 10)! == (551.175 * 100) คุณต้องใช้การเพิ่มทศนิยมเพื่อย้ายเครื่องหมายจุลภาคสำหรับผลลัพธ์ทศนิยมที่ไม่ใช่ของจริง
Kir Kanos

+1 สำหรับการสังเกตสิ่งนี้อย่างไรก็ตามtoFixedได้รับผลกระทบเช่นกัน - (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)... ใช้วิธีใดวิธีหนึ่งให้เพิ่มเอปไซลอนก่อนการปัดเศษ
Skippy le Grand Gourou

5

กุญแจที่นี่ฉันเดาคือการปัดเศษขึ้นอย่างถูกต้องก่อนจากนั้นคุณสามารถแปลงเป็นสตริง

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

ตอนนี้คุณสามารถจัดรูปแบบค่านี้ได้อย่างปลอดภัยด้วย toFixed (p) ดังนั้นด้วยกรณีเฉพาะของคุณ:

roundOf(0.3445434, 2).toFixed(2); // 0.34

3

หากคุณต้องการสตริงโดยไม่ต้องปัดคุณสามารถใช้ RegEx นี้ (อาจไม่ใช่วิธีที่มีประสิทธิภาพที่สุด ... แต่มันง่ายมาก)

(2.34567778).toString().match(/\d+\.\d{2}/)[0]
// '2.34'

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

คำตอบที่ดียกเว้นว่าคุณขาดเครื่องหมายอัฒภาค (ไม่, ในเครื่องหมายอัฒภาค es6 ไม่ล้าสมัยและเรายังต้องใช้พวกเขาในบางกรณี) ฉันได้ไปยังแก้ไขแถวสุดท้ายที่: return float_part ? int_part+'.'+float_part : int_part;มิฉะนั้นถ้าคุณผ่านจำนวนเต็มก็กลับจำนวนด้วยจุดที่สิ้นสุด (input ตัวอย่างเช่น: 2100เอาท์พุท: 2100.)
คิวบา Simonovsky

0

บางทีคุณอาจต้องการตัวแยกทศนิยม นี่คือฟังก์ชั่นที่ฉันเพิ่งทำ:

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

0

ไม่มีวิธีที่จะหลีกเลี่ยงการปัดเศษราคาที่ไม่สอดคล้องกับ x.xx5 เป็นค่าจริงโดยใช้การคูณหรือการหาร หากคุณต้องการคำนวณราคาที่ถูกต้องฝั่งลูกค้าคุณควรเก็บยอดเงินทั้งหมดเป็นเซ็นต์ นี่เป็นเพราะธรรมชาติของการเป็นตัวแทนภายในของค่าตัวเลขใน JavaScript ขอให้สังเกตว่า Excel ทนทุกข์ทรมานจากปัญหาเดียวกันดังนั้นคนส่วนใหญ่จะไม่สังเกตเห็นข้อผิดพลาดเล็ก ๆ ที่เกิดจากปรากฏการณ์นี้ อย่างไรก็ตามข้อผิดพลาดอาจสะสมเมื่อใดก็ตามที่คุณเพิ่มค่าที่คำนวณได้จำนวนมากมีทฤษฎีทั้งหมดเกี่ยวกับลำดับของการคำนวณและวิธีการอื่น ๆ เพื่อลดข้อผิดพลาดในผลลัพธ์สุดท้าย เพื่อเน้นปัญหาเกี่ยวกับค่าทศนิยมโปรดทราบว่า 0.1 + 0.2 ไม่เท่ากับ 0.3 ใน JavaScript ในขณะที่ 1 + 2 เท่ากับ 3


การแก้ปัญหาคือการแยกส่วนทั้งหมดและส่วนทศนิยมและแสดงให้พวกเขาเป็นจำนวนเต็มในฐาน 10 แทนการใช้ลอยที่นี่มันทำงานได้โดยไม่มีปัญหาสำหรับ prettyPrint แต่โดยทั่วไปคุณต้องเลือกระหว่างฐานและอื่นแทนสำหรับ ตัวเลขจริงและอื่น ๆ แต่ละตัวมีปัญหา
ใหม่

"Excel ทนทุกข์จากปัญหาเดียวกัน" แหล่งที่มา?
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"

0

ฉันใช้รหัสนี้เพื่อจัดรูปแบบลอยตัว มันขึ้นอยู่กับtoPrecision()แต่มันแถบศูนย์ที่ไม่จำเป็น ฉันยินดีรับข้อเสนอแนะเกี่ยวกับวิธีทำให้ regex ง่ายขึ้น

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

ตัวอย่างการใช้งาน:

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>');
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.