ตัดทอนเลขทศนิยมสองตำแหน่งโดยไม่ปัดเศษ


196

สมมติว่าฉันมีค่า 15.7784514 ฉันต้องการแสดง 15.77 โดยไม่มีการปัดเศษ

var num = parseFloat(15.7784514);
document.write(num.toFixed(1)+"<br />");
document.write(num.toFixed(2)+"<br />");
document.write(num.toFixed(3)+"<br />");
document.write(num.toFixed(10));

ผลลัพธ์ใน -

15.8
15.78
15.778
15.7784514000 

ฉันจะแสดง 15.77 ได้อย่างไร


3
ฉันอยากถามว่าทำไมคุณไม่ต้องการปัดเศษ ดูเหมือนว่าไม่ถูกต้องไม่ว่าที่ไหน ...
Camilo Martin

39
มันมีประโยชน์เมื่อแสดงสกุลเงิน
Richard Ye

@ mik01aj - เมื่อแสดงสกุลเงินมันเป็นเรื่องธรรมดามากที่จะตัดทอนค่าที่คำนวณได้แทนที่จะปัดเศษพวกมัน ตัวอย่างเช่นรูปแบบภาษีส่วนใหญ่ในสหรัฐอเมริกาจะถูกปัดเศษแทนที่จะเป็นเศษส่วนที่คำนวณได้ ในกรณีนั้นค่าที่ถูกตัดทอนเป็นค่าที่ถูกต้อง
Steven Byks

4
@CamiloMartin มีความแตกต่างอย่างมากระหว่างหนี้ 1.49 พันล้านดอลลาร์และ 1.0 พันล้านดอลลาร์
Broda Noel

3
นอกจากนี้ยังมีความแตกต่างอย่างมากระหว่าง 1.49 พันล้านถึง 1.50 พันล้านดอลลาร์ นั่นคือ $ 100 ล้าน
Liga

คำตอบ:


228

แปลงตัวเลขเป็นสตริงจับคู่ตัวเลขให้เป็นทศนิยมสองตำแหน่ง:

function calc(theform) {
    var num = theform.original.value, rounded = theform.rounded
    var with2Decimals = num.toString().match(/^-?\d+(?:\.\d{0,2})?/)[0]
    rounded.value = with2Decimals
}
<form onsubmit="return calc(this)">
Original number: <input name="original" type="text" onkeyup="calc(form)" onchange="calc(form)" />
<br />"Rounded" number: <input name="rounded" type="text" placeholder="readonly" readonly>
</form>

toFixedวิธีการล้มเหลวในบางกรณีแตกต่างtoStringจึงควรระมัดระวังมากกับมัน


22
+1 นั่นควรแก้ปัญหาการปัดเศษ ฉันยังคงต้องการการส่งออกผลมาจากด้านบนโดยใช้แต่เพื่อ:toFixed (Math.floor(value * 100) / 100).toFixed(2)อย่างที่คุณอาจจะรู้ว่าสิ่งที่มีความแม่นยำแปลก ๆ สามารถเกิดขึ้นได้กับค่าจุดลอยตัว (และอีกด้านหนึ่งของสเปกตรัมถ้าจำนวนนั้นเป็น15เช่น15.00นั้น
TJ Crowder

1
ฮิฮิหรือถ้าคุณรวมทั้ง:Number((15.7784514000*100).toString().match(/^\d+/)/100);
skobaljic

27
Math.floor (ค่า * 100) / 100 จะไม่ทำงานหาก value = 4.27 จริงจังลองดู
Dark Hippo

3
@DarkHippo Thats เพราะ 4.27 คือ 4.26999999999 โดยทั่วไป Math.round เป็นคำตอบที่ดีกว่าแม้ว่าจะไม่ใช่คำตอบสำหรับคำถามดั้งเดิม ผลลัพธ์ที่ได้รับตามจริงคือสตริงที่ควรทำโดยใช้การจัดการสตริงแทนวิธีแก้ปัญหาตัวเลขที่มีจุดลอยตัวทั้งหมด
BJury

3
... ที่ไม่ถูกต้อง การแปลงระหว่างประเภทภายใต้สถานการณ์ใด ๆ ดูเหมือนว่าวงเวียนและไม่ปลอดภัย เว้นแต่โปรแกรมเมอร์ขั้นสูงจริงๆจะยืนยันว่า "ทุกประเภทเป็นแค่สตรีม" หรืออะไรบางอย่าง
JackHasaKeyboard

66

อัปเดต 5 พฤศจิกายน 2559

คำตอบใหม่ถูกต้องเสมอ

function toFixed(num, fixed) {
    var re = new RegExp('^-?\\d+(?:\.\\d{0,' + (fixed || -1) + '})?');
    return num.toString().match(re)[0];
}

เนื่องจากคณิตศาสตร์เลขทศนิยมในจาวาสคริปต์จะมีกรณีขอบอยู่เสมอวิธีแก้ไขปัญหาก่อนหน้านี้จะแม่นยำเกือบตลอดเวลาซึ่งไม่ดีพอ มีการแก้ปัญหาบางอย่างเช่นนี้มีnum.toPrecision, BigDecimal.jsและaccounting.js แต่ฉันเชื่อว่าการแยกสตริงจะง่ายและแม่นยำที่สุดเสมอ

หากเป็นการอัพเดตบน regex ที่เขียนอย่างดีจากคำตอบที่ยอมรับโดย @Gumbo ฟังก์ชัน toFixed ใหม่นี้จะทำงานได้ตามปกติ


คำตอบเก่าไม่ถูกต้องเสมอไป

หมุนฟังก์ชัน toFixed ของคุณเอง:

function toFixed(num, fixed) {
    fixed = fixed || 0;
    fixed = Math.pow(10, fixed);
    return Math.floor(num * fixed) / fixed;
}

7
toFixed (4.56, 2) = 4.55
cryss

2
คำตอบเหล่านี้จำนวนมากมีการคูณภายในฟังก์ชัน Math.floor () สิ่งนี้จะล้มเหลวในบางหมายเลข! การคำนวณเลขทศนิยมไม่ถูกต้องและคุณต้องใช้วิธีการที่แตกต่างกัน
Nico Westerdale

1
ฟังก์ชั่น toFixedCustom (จำนวนคงที่) {var re = new RegExp ('^ -? \\ d + (?: \. \\ d {0,' + (คงที่ || -1) + '})?'); if (num.toString (). match (re)) {return num.toString (). match (อีกครั้ง) [0]; }}
Ryan Augustine

1
คำตอบที่ปรับปรุงแล้วจะล้มเหลวสำหรับจำนวนเล็กหรือใหญ่พอที่จาวาสคริปต์จะแสดงในสัญลักษณ์ทางวิทยาศาสตร์ toFixed(0.0000000052, 2)อัตราผลตอบแทน '5.2' สิ่งนี้สามารถแก้ไขได้โดยใช้การreturn num.toFixed(fixed+1).match(re)[0];แจ้งเตือนที่ฉันใช้เพื่อแก้ไขด้วยทศนิยมหนึ่งตำแหน่งเหนือเป้าหมายเพื่อหลีกเลี่ยงการปัดเศษแล้วเรียกใช้การจับคู่ regex ของคุณ
Netherdan

34

ฉันเลือกที่จะเขียนสิ่งนี้แทนการลบส่วนที่เหลือด้วยสตริงด้วยตนเองดังนั้นฉันจึงไม่ต้องจัดการกับปัญหาทางคณิตศาสตร์ที่มาพร้อมกับตัวเลข:

num = num.toString(); //If it's not already a String
num = num.slice(0, (num.indexOf("."))+3); //With 3 exposing the hundredths place
Number(num); //If you need it back as a Number

สิ่งนี้จะให้ "15.77" กับ num = 15.7784514;


5
หากคุณไม่ได้บังคับให้ใช้ทศนิยมคุณอาจต้องการเพิ่มเงื่อนไขในกรณีที่คุณพบจำนวนเต็ม เช่นนี้: num = num.toString (); if (num.indexOf (".")> 0) {num = num.slice (0, (num.indexOf (".")) + 3)}; จำนวน (NUM);
ベンノスケ

1
ดีถ้ามันมีทศนิยม แต่ถ้ามันเป็นจำนวนเต็มมันจะล้มเหลว
Ruslan López

หากตัวเลขคือ 0.00000052 แสดงว่าผิดจะได้รับ 5.2e
Vasanth

1
@Vasanth หากตัวเลขคือ 0.00000052 จะส่งคืน "0.00" อาจมีการแก้ไขคำตอบตั้งแต่
Drenai

ใช่มันล้มเหลวในกรณีขอบ
VPaul

18

ตุลาคม 2017

วิธีการแก้ปัญหาทั่วไปในการตัด (ไม่มีการปัดเศษ) ตัวเลขเป็นตัวเลขทศนิยมที่ n และแปลงเป็นสตริงที่มีตัวเลขทศนิยม n ตำแหน่งแน่นอนสำหรับn≥0ใด ๆ

function toFixedTrunc(x, n) {
  const v = (typeof x === 'string' ? x : x.toString()).split('.');
  if (n <= 0) return v[0];
  let f = v[1] || '';
  if (f.length > n) return `${v[0]}.${f.substr(0,n)}`;
  while (f.length < n) f += '0';
  return `${v[0]}.${f}`
}

โดยที่ x สามารถเป็นได้ทั้งตัวเลข (ซึ่งได้รับการแปลงเป็นสตริง) หรือสตริง

นี่คือการทดสอบบางอย่างสำหรับ n = 2 (รวมถึงการทดสอบที่ร้องขอโดย OP):

0           => 0.00
0.01        => 0.01
0.5839      => 0.58
0.999       => 0.99
1.01        => 1.01
2           => 2.00
2.551       => 2.55
2.99999     => 2.99
4.27        => 4.27
15.7784514  => 15.77
123.5999    => 123.59
0.000000199 => 1.99 *

* ดังที่กล่าวไว้ในบันทึกย่อนั่นเป็นเพราะการแปลงจาวาสคริปต์โดยปริยายเป็นเลขชี้กำลังสำหรับ "1.99e-7" และสำหรับค่าอื่น ๆ ของ n:

15.001097   => 15.0010 (n=4)
0.000003298 => 0.0000032 (n=7)
0.000003298257899 => 0.000003298257 (n=12)

2
toFixedTrunc(0.000000199, 2) // 1.99
Maharramoff

1
@ShamkhalMaharramov: ถ้าคุณเปิดคอนโซลการพัฒนาและป้อน 0.000000199 คุณจะได้อะไร คุณได้รับ 1.99e-7 นอกจากนี้หากคุณป้อน 0.000000199.toString () คุณจะได้อะไร คุณจะได้รับ "1.99e-7" ดังนั้นเมื่อคุณผ่าน 0.000000199 ไปยังฟังก์ชั่นมันจะจบลงด้วยการทำงานกับ "1.99e-7" ไม่ใช่ "0.000000199" และ "ถูกต้อง" จะส่งกลับ "1.99" ดูecma-international.org/ecma-262/6.0/…
SC1000

13

parseInt เร็วกว่า Math.floor

function floorFigure(figure, decimals){
    if (!decimals) decimals = 2;
    var d = Math.pow(10,decimals);
    return (parseInt(figure*d)/d).toFixed(decimals);
};

floorFigure(123.5999)    =>   "123.59"
floorFigure(123.5999, 3) =>   "123.599"

2
มันล้มเหลวด้วย 1234567.89
Ruslan López

คุณช่วยอธิบายโลเปซอย่างละเอียดได้ไหม?
zardilior

3
floorFigure (4.56, 2) = 4.55
cryss

7
num = 19.66752
f = num.toFixed(3).slice(0,-1)
alert(f)

สิ่งนี้จะส่งคืน 19.66


5
(4.9999) .toFixed (3) .slice (0, -1) ผลตอบแทน 5.00 ผลลัพธ์ที่คาดหวังคือ 4.99
Bruno Lemos

1
ฉันแนะนำให้ใช้บางอย่างเช่น. toFixed (6) .slice (0, -4) แทน
Bruno Lemos

มันสมบูรณ์แบบในกรณีของฉันมันก็โอเค เช่นถ้าฉันต้องการมีเพียงหนึ่งเลขทศนิยมใช้ num.toFixed (2) .slice (0, -1) (ถ้า num มี 1.2356 มันจะกลับ 1.2)
Esteban Perez


5

วิธีแก้ปัญหาเหล่านี้ใช้งานได้ แต่สำหรับฉันดูเหมือนจะซับซ้อนโดยไม่จำเป็น ฉันชอบใช้โมดูลัสโอเปอเรเตอร์เพื่อรับส่วนที่เหลือของการดำเนินการหารและลบออก สมมติว่า NUM = 15.7784514:

num-=num%.01;

นี่เทียบเท่ากับการพูด num = num - (num% .01)


นั่นเป็นนิชกุนที่น่าสนใจขอบคุณที่ชี้ให้เห็น ฉันไม่เคยพบปัญหาในการใช้เทคนิคนี้ แต่เห็นได้ชัดว่าฉันควรตรวจสอบตัวอย่างเช่นนี้ให้ละเอียดยิ่งขึ้น คุณสามารถใช้ ((num * = 100) - (num% 1)) / 100 ซึ่งแก้ปัญหานี้ได้ ลำดับความสำคัญในกรณีของฉันคือความเร็วในการประมวลผลเนื่องจากปริมาณการคำนวณที่ฉันใช้กับสิ่งนี้และนี่เป็นวิธีที่เร็วที่สุดในการบรรลุเป้าหมายที่ฉันได้พบ
jtrick

1
ประเด็นคือเพื่อหลีกเลี่ยงการค้นหาวัตถุและฟังก์ชั่นและการแปลงที่จำเป็นในการแก้ปัญหาอื่น ๆ ที่นำเสนอ ขอบคุณสำหรับความคิดเห็น!
jtrick

1
ก็ล้มเหลวด้วยเชิงลบเป็น -5
Ruslan López

ฉันสนใจที่จะปัดเศษอย่างรวดเร็วคุณจะทำให้โค้ดนี้มีทศนิยม 1 อย่างไร?
thednp

5

คำตอบที่นี่ไม่ได้ช่วยฉันมันเก็บไว้ปัดเศษขึ้นหรือให้ทศนิยมผิด

โซลูชันของฉันแปลงทศนิยมเป็นสตริงแยกอักขระแล้วส่งกลับเป็นจำนวนทั้งหมด

function Dec2(num) {
  num = String(num);
  if(num.indexOf('.') !== -1) {
    var numarr = num.split(".");
    if (numarr.length == 1) {
      return Number(num);
    }
    else {
      return Number(numarr[0]+"."+numarr[1].charAt(0)+numarr[1].charAt(1));
    }
  }
  else {
    return Number(num);
  }  
}

Dec2(99); // 99
Dec2(99.9999999); // 99.99
Dec2(99.35154); // 99.35
Dec2(99.8); // 99.8
Dec2(10265.985475); // 10265.98

Dec2 (99) ควรกลับ 99.00
VPaul

5

รุ่นของฉันสำหรับจำนวนบวก:

function toFixed_norounding(n,p)
{
    var result = n.toFixed(p);
    return result <= n ? result: (result - Math.pow(0.1,p)).toFixed(p);
}

เร็ว, สวย, ชัดเจน (เวอร์ชั่นสำหรับตัวเลขบวก)


จำเป็นต้องมีการปัดเศษสำหรับค่าทศนิยม (เช่นเงิน) โดยมีทศนิยมเพียง 1 ค่า ฟังก์ชั่นด้านบนควรเป็น "คำตอบ" ของหัวข้อนี้มันยอดเยี่ยมใช้งานได้อย่างมีเสน่ห์ ขอบคุณผู้เขียน & ขอบคุณ :)))
Adrian Tanase

ล้มเหลวสำหรับค่าลบ -0.7752. ทดสอบ toFixed_norounding(-0.7752,2)ผลตอบแทน-0.78แทน-0.77
Ling Loeng

4

รหัสต่อไปนี้ทำงานได้ดีมากสำหรับฉัน:

num.toString().match(/.\*\\..{0,2}|.\*/)[0];

ฉันจะเพิ่มเครื่องหมายลบตัวเลือกที่จะทำให้มันสมบูรณ์แบบ-?;)
Ruslan López

3

ฉันคงใช้วิธีง่ายๆดังต่อไปนี้ -

var num = 15.7784514;
Math.floor(num*100)/100;

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


ไม่ทำงานกับค่าลบ: -15.7784514ส่งคืน-15.78
Clément Baconnier

3

เพียงตัดทอนตัวเลข:

function truncDigits(inputNumber, digits) {
  const fact = 10 ** digits;
  return Math.floor(inputNumber * fact) / fact;
}

3

โซลูชันบรรทัดเดียวอื่น:

number = Math.trunc(number*100)/100

ฉันใช้ 100 เพราะคุณต้องการตัดให้เหลือสองหลัก แต่วิธีแก้ปัญหาที่ยืดหยุ่นกว่าคือ:

number = Math.trunc(number*Math.pow(10, digits))/Math.pow(10, digits)

โดยที่ Digit คือจำนวนตัวเลขทศนิยมที่จะเก็บ

ดูรายละเอียด Math.truncสำหรับรายละเอียดและความเข้ากันได้ของเบราว์เซอร์


1
นี่คือคำตอบที่ดีที่สุดหากคุณไม่ต้องรองรับ IE11
TJ

2

อยู่นี่ไง. คำตอบที่แสดงอีกวิธีหนึ่งในการแก้ปัญหา:

// For the sake of simplicity, here is a complete function:
function truncate(numToBeTruncated, numOfDecimals) {
    var theNumber = numToBeTruncated.toString();
    var pointIndex = theNumber.indexOf('.');
    return +(theNumber.slice(0, pointIndex > -1 ? ++numOfDecimals + pointIndex : undefined));
}

สังเกตการใช้ + ก่อนนิพจน์สุดท้าย นั่นคือการแปลงสตริงที่ถูกตัดทอนของเรากลับเป็นประเภทตัวเลข

หวังว่ามันจะช่วย!


1
ฉันชอบความเรียบง่ายของวิธีการนี้และฉันรู้สึกว่าวิธีแก้ปัญหาทั้งหมดที่หลีกเลี่ยงการใช้คณิตศาสตร์นั้นเหมาะสมกว่าสำหรับการแก้ปัญหานี้ ดังนั้นการใช้ slice () เป็นต้นเป็นวิธีที่ถูกต้องในการส่งต่อ ข้อดีเพียงอย่างเดียวของวิธีการของฉันคือมันจะประมวลผลตัวเลขที่ส่งผ่านในที่เป็นสตริง [ล้อมรอบด้วยเครื่องหมายคำพูด [เดี่ยว / คู่]] ด้วยเหตุผลบางอย่างฟังก์ชั่นด้านบนมีข้อผิดพลาดใน FF เมื่อฉันทำ: console.log ('truncate ("0.85156", 2)', ตัด ("0.85156", 2));
Charles Robertson

2

ตัดโดยไม่มีศูนย์

function toTrunc(value,n){  
    return Math.floor(value*Math.pow(10,n))/(Math.pow(10,n));
}

หรือ

function toTrunc(value,n){
    x=(value.toString()+".0").split(".");
    return parseFloat(x[0]+"."+x[1].substr(0,n));
}

ทดสอบ:

toTrunc(17.4532,2)  //17.45
toTrunc(177.4532,1) //177.4
toTrunc(1.4532,1)   //1.4
toTrunc(.4,2)       //0.4

ตัดทอนด้วยเลขศูนย์

function toTruncFixed(value,n){
    return toTrunc(value,n).toFixed(n);
}

ทดสอบ:

toTrunc(17.4532,2)  //17.45
toTrunc(177.4532,1) //177.4
toTrunc(1.4532,1)   //1.4
toTrunc(.4,2)       //0.40

2

นี้ทำงานได้ดีสำหรับฉัน. ฉันหวังว่ามันจะแก้ไขปัญหาของคุณด้วย

function toFixedNumber(number) {
    const spitedValues = String(number.toLocaleString()).split('.');
    let decimalValue = spitedValues.length > 1 ? spitedValues[1] : '';
    decimalValue = decimalValue.concat('00').substr(0,2);

    return '$'+spitedValues[0] + '.' + decimalValue;
}

// 5.56789      ---->  $5.56
// 0.342        ---->  $0.34
// -10.3484534  ---->  $-10.34 
// 600          ---->  $600.00

function convertNumber(){
  var result = toFixedNumber(document.getElementById("valueText").value);
  document.getElementById("resultText").value = result;
}


function toFixedNumber(number) {
        const spitedValues = String(number.toLocaleString()).split('.');
        let decimalValue = spitedValues.length > 1 ? spitedValues[1] : '';
        decimalValue = decimalValue.concat('00').substr(0,2);

        return '$'+spitedValues[0] + '.' + decimalValue;
}
<div>
  <input type="text" id="valueText" placeholder="Input value here..">
  <br>
  <button onclick="convertNumber()" >Convert</button>
  <br><hr>
  <input type="text" id="resultText" placeholder="result" readonly="true">
</div>


2

วิธีง่าย ๆ ที่จะทำคือถัดไป แต่จำเป็นต้องตรวจสอบให้แน่ใจว่าได้กำหนดพารามิเตอร์จำนวนเป็นสตริง

function truncate(amountAsString, decimals = 2){
  var dotIndex = amountAsString.indexOf('.');
  var toTruncate = dotIndex !== -1  && ( amountAsString.length > dotIndex + decimals + 1);
  var approach = Math.pow(10, decimals);
  var amountToTruncate = toTruncate ? amountAsString.slice(0, dotIndex + decimals +1) : amountAsString;  
  return toTruncate
    ?  Math.floor(parseFloat(amountToTruncate) * approach ) / approach
    :  parseFloat(amountAsString);

}

console.log(truncate("7.99999")); //OUTPUT ==> 7.99
console.log(truncate("7.99999", 3)); //OUTPUT ==> 7.999
console.log(truncate("12.799999999999999")); //OUTPUT ==> 7.99

2

function formatLimitDecimals(value, decimals) {
  value = value.toString().split('.')

  if (value.length === 2) {
    return Number([value[0], value[1].slice(0, decimals)].join('.'))
  } else {
    return Number(value[0]);
  }
}

console.log(formatLimitDecimals(4.156, 2)); // 4.15
console.log(formatLimitDecimals(4.156, 8)); // 4.156
console.log(formatLimitDecimals(4.156, 0)); // 4



1

โซลูชันของฉันใน typescript (สามารถย้ายไปยัง JS ได้อย่างง่ายดาย):

/**
 * Returns the price with correct precision as a string
 *
 * @param   price The price in decimal to be formatted.
 * @param   decimalPlaces The number of decimal places to use
 * @return  string The price in Decimal formatting.
 */
type toDecimal = (price: number, decimalPlaces?: number) => string;
const toDecimalOdds: toDecimal = (
  price: number,
  decimalPlaces: number = 2,
): string => {
  const priceString: string = price.toString();
  const pointIndex: number = priceString.indexOf('.');

  // Return the integer part if decimalPlaces is 0
  if (decimalPlaces === 0) {
    return priceString.substr(0, pointIndex);
  }

  // Return value with 0s appended after decimal if the price is an integer
  if (pointIndex === -1) {
    const padZeroString: string = '0'.repeat(decimalPlaces);

    return `${priceString}.${padZeroString}`;
  }

  // If numbers after decimal are less than decimalPlaces, append with 0s
  const padZeroLen: number = priceString.length - pointIndex - 1;
  if (padZeroLen > 0 && padZeroLen < decimalPlaces) {
    const padZeroString: string = '0'.repeat(padZeroLen);

    return `${priceString}${padZeroString}`;
  }

  return priceString.substr(0, pointIndex + decimalPlaces + 1);
};

กรณีทดสอบ:

  expect(filters.toDecimalOdds(3.14159)).toBe('3.14');
  expect(filters.toDecimalOdds(3.14159, 2)).toBe('3.14');
  expect(filters.toDecimalOdds(3.14159, 0)).toBe('3');
  expect(filters.toDecimalOdds(3.14159, 10)).toBe('3.1415900000');
  expect(filters.toDecimalOdds(8.2)).toBe('8.20');

การปรับปรุงใด ๆ


0

สะสมtoFixedฟังก์ชั่นของคุณเอง: สำหรับค่าบวกMath.floorทำงานได้ดี

function toFixed(num, fixed) {
    fixed = fixed || 0;
    fixed = Math.pow(10, fixed);
    return Math.floor(num * fixed) / fixed;
}

สำหรับค่าลบMath.floorคือรอบของค่า ดังนั้นคุณสามารถใช้Math.ceilแทน

ตัวอย่าง,

Math.ceil(-15.778665 * 10000) / 10000 = -15.7786
Math.floor(-15.778665 * 10000) / 10000 = -15.7787 // wrong.

5
คำตอบเหล่านี้จำนวนมากมีการคูณภายในฟังก์ชัน Math.floor () สิ่งนี้จะล้มเหลวในบางหมายเลข! การคำนวณเลขทศนิยมไม่ถูกต้องและคุณต้องใช้วิธีการที่แตกต่างกัน
Nico Westerdale

0

คำตอบที่สองของ Gumbo ซึ่งมีนิพจน์ทั่วไปนั้นใช้งานได้ แต่ช้าเพราะนิพจน์ทั่วไป การแก้ปัญหาแรกของ Gumbo ล้มเหลวในบางสถานการณ์เนื่องจากไม่แม่นยำในจำนวนคะแนนลอยตัว ดูJSFiddleสำหรับการสาธิตและเกณฑ์มาตรฐาน โซลูชันที่สองใช้เวลาประมาณ 1,636 นาโนวินาทีต่อการโทรหนึ่งครั้งบนระบบปัจจุบันของฉันคือ Intel Core i5-2500 CPU ที่ 3.30 GHz

วิธีแก้ปัญหาที่ฉันเขียนเกี่ยวข้องกับการเพิ่มค่าตอบแทนเล็กน้อยเพื่อดูแลจุดที่ไม่แน่นอน มันเป็นพื้นทันทีคือตามคำสั่งของ nanoseconds ฉันโอเวอร์คล็อก 2 nanoseconds ต่อการโทร แต่ตัวจับเวลา JavaScript ไม่แม่นยำหรือละเอียดมาก นี่คือซอ Fiddleและรหัส

function toFixedWithoutRounding (value, precision)
{
    var factorError = Math.pow(10, 14);
    var factorTruncate = Math.pow(10, 14 - precision);
    var factorDecimal = Math.pow(10, precision);
    return Math.floor(Math.floor(value * factorError + 1) / factorTruncate) / factorDecimal;
}

var values = [1.1299999999, 1.13, 1.139999999, 1.14, 1.14000000001, 1.13 * 100];

for (var i = 0; i < values.length; i++)
{
    var value = values[i];
    console.log(value + " --> " + toFixedWithoutRounding(value, 2));
}

for (var i = 0; i < values.length; i++)
{
    var value = values[i];
    console.log(value + " --> " + toFixedWithoutRounding(value, 4));
}

console.log("type of result is " + typeof toFixedWithoutRounding(1.13 * 100 / 100, 2));

// Benchmark
var value = 1.13 * 100;
var startTime = new Date();
var numRun = 1000000;
var nanosecondsPerMilliseconds = 1000000;

for (var run = 0; run < numRun; run++)
    toFixedWithoutRounding(value, 2);

var endTime = new Date();
var timeDiffNs = nanosecondsPerMilliseconds * (endTime - startTime);
var timePerCallNs = timeDiffNs / numRun;
console.log("Time per call (nanoseconds): " + timePerCallNs);

0

อาคารเดวิด D'sคำตอบ:

function NumberFormat(num,n) {
  var num = (arguments[0] != null) ? arguments[0] : 0;
  var n = (arguments[1] != null) ? arguments[1] : 2;
  if(num > 0){
    num = String(num);
    if(num.indexOf('.') !== -1) {
      var numarr = num.split(".");
      if (numarr.length > 1) {
        if(n > 0){
          var temp = numarr[0] + ".";
          for(var i = 0; i < n; i++){
            if(i < numarr[1].length){
              temp += numarr[1].charAt(i);
            }
          }
          num = Number(temp);
        }
      }
    }
  }
  return Number(num);
}

console.log('NumberFormat(123.85,2)',NumberFormat(123.85,2));
console.log('NumberFormat(123.851,2)',NumberFormat(123.851,2));
console.log('NumberFormat(0.85,2)',NumberFormat(0.85,2));
console.log('NumberFormat(0.851,2)',NumberFormat(0.851,2));
console.log('NumberFormat(0.85156,2)',NumberFormat(0.85156,2));
console.log('NumberFormat(0.85156,4)',NumberFormat(0.85156,4));
console.log('NumberFormat(0.85156,8)',NumberFormat(0.85156,8));
console.log('NumberFormat(".85156",2)',NumberFormat(".85156",2));
console.log('NumberFormat("0.85156",2)',NumberFormat("0.85156",2));
console.log('NumberFormat("1005.85156",2)',NumberFormat("1005.85156",2));
console.log('NumberFormat("0",2)',NumberFormat("0",2));
console.log('NumberFormat("",2)',NumberFormat("",2));
console.log('NumberFormat(85156,8)',NumberFormat(85156,8));
console.log('NumberFormat("85156",2)',NumberFormat("85156",2));
console.log('NumberFormat("85156.",2)',NumberFormat("85156.",2));

// NumberFormat(123.85,2) 123.85
// NumberFormat(123.851,2) 123.85
// NumberFormat(0.85,2) 0.85
// NumberFormat(0.851,2) 0.85
// NumberFormat(0.85156,2) 0.85
// NumberFormat(0.85156,4) 0.8515
// NumberFormat(0.85156,8) 0.85156
// NumberFormat(".85156",2) 0.85
// NumberFormat("0.85156",2) 0.85
// NumberFormat("1005.85156",2) 1005.85
// NumberFormat("0",2) 0
// NumberFormat("",2) 0
// NumberFormat(85156,8) 85156
// NumberFormat("85156",2) 85156
// NumberFormat("85156.",2) 85156

0

มีความน่าเชื่อถือมากขึ้นในการรับคะแนนลอยสองจุดโดยไม่ต้องปัดเศษ

คำตอบอ้างอิง

var number = 10.5859;
var fixed2FloatPoints = parseInt(number * 100) / 100;
console.log(fixed2FloatPoints);

ขอบคุณ !


0

มีคำตอบที่เหมาะสมสำหรับการคำนวณนิพจน์ทั่วไปและการคำนวณทางคณิตศาสตร์แล้วคุณสามารถลองทำสิ่งนี้ได้

function myFunction() {
    var str = 12.234556; 
    str = str.toString().split('.');
    var res = str[1].slice(0, 2);
    document.getElementById("demo").innerHTML = str[0]+'.'+res;
}

// output: 12.23

0

นี่คือสิ่งที่มันทำกับสตริง

export function withoutRange(number) {
  const str = String(number);
  const dotPosition = str.indexOf('.');
  if (dotPosition > 0) {
    const length = str.substring().length;
    const end = length > 3 ? 3 : length;
    return str.substring(0, dotPosition + end);
  }
  return str;
}

0

คำตอบทั้งหมดเหล่านี้ดูเหมือนจะซับซ้อนเล็กน้อย ฉันจะลบ 0.5 จากหมายเลขของคุณและใช้ toFixed ()


คุณหมายถึง 0.005?
Luan Nguyen

0

ทางออกที่มีประสิทธิภาพมากที่สุด (สำหรับตัวเลข 2 หลัก) คือการลบ 0.005 ก่อนการโทร toFixed()

function toFixed2( num ) { return (num-0.005).toFixed(2) }

ตัวเลขลบจะถูกปัดเศษลงเช่นกัน (ห่างจากศูนย์) OP ไม่ได้บอกอะไรเกี่ยวกับตัวเลขลบ


0

ฉันรู้ว่ามีตัวอย่างการทำงานอยู่เล็กน้อย แต่ฉันคิดว่ามันคุ้มค่าที่จะเสนอ String ของฉันหากเทียบกันแล้วบางคนอาจเห็นว่าเป็นประโยชน์

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

function toFixedFixed(value, precision = 0) {
    let stringValue = isNaN(+value) ? '0' : String(+value);

    if (stringValue.indexOf('e') > -1 || stringValue === 'Infinity' || stringValue === '-Infinity') {
        throw new Error('To large number to be processed');
    }

    let [ beforePoint, afterPoint ] = stringValue.indexOf('.') > -1 ? stringValue.split('.') : [ stringValue, ''];

    // Force automatic rounding for some long real numbers that ends with 99X, by converting it to string, cutting off last digit, then adding extra nines and casting it on number again
    // e.g. 2.0199999999999996: +('2.019999999999999' + '9999') will give 2.02
    if (stringValue.length >= 17 && afterPoint.length > 2 && +afterPoint.substr(afterPoint.length - 3) > 995) {
        stringValue = String(+(stringValue.substr(0, afterPoint.length - 1) + '9'.repeat(stringValue.split('.').shift().length + 4)));
        [ beforePoint, afterPoint ] = String(stringValue).indexOf('.') > -1 ? stringValue.split('.') : [ stringValue, ''];
    }

    if (precision === 0) {
        return beforePoint;
    } else if (afterPoint.length > precision) {
        return `${beforePoint}.${afterPoint.substr(0, precision)}`;
    } else {
        return `${beforePoint}.${afterPoint}${'0'.repeat(precision - afterPoint.length)}`;
    }
}

โปรดทราบว่าอาจไม่สามารถจัดการความแม่นยำอย่างถูกต้องสำหรับจำนวนความยาว 18 ขึ้นไปเช่น Chrome 64 บิตจะปัดเศษหรือเพิ่ม "e +" / "e-" เพื่อรักษาความยาวของตัวเลขไว้ที่ 18

หากคุณต้องการดำเนินการกับตัวเลขจริงมันปลอดภัยกว่าที่จะคูณด้วยMath.sqrt(10, precision)ครั้งแรกทำการคำนวณแล้วดำน้ำผลลัพธ์โดยค่าของตัวคูณ

ตัวอย่าง:

0.06 + 0.01เป็น0.06999999999999999และทุกฟังก์ชั่นการจัดรูปแบบที่ไม่ปัดเศษจะตัดมันเพื่อความแม่นยำ0.062

แต่ถ้าคุณจะดำเนินการเช่นเดียวกันกับการคูณและหาร: คุณจะได้รับ(0.06 * 100 + 0.01 * 100) / 1000.07

นั่นเป็นเหตุผลที่มันสำคัญมากที่จะใช้ตัวคูณ / ตัวหารเมื่อจัดการกับตัวเลขจริงในจาวาสคริปต์โดยเฉพาะเมื่อคุณคำนวณเงิน ...

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