ฉันกำลังพยายามตัดทอนตัวเลขทศนิยมให้เป็นทศนิยม สิ่งนี้:
5.467 -> 5.46
985.943 -> 985.94
toFixed(2)
ไม่เกี่ยวกับสิ่งที่ถูกต้อง แต่จะปัดเศษค่า ฉันไม่ต้องการให้ค่าถูกปัดเศษ หวังว่าสิ่งนี้จะเป็นไปได้ในจาวาสคริปต์
ฉันกำลังพยายามตัดทอนตัวเลขทศนิยมให้เป็นทศนิยม สิ่งนี้:
5.467 -> 5.46
985.943 -> 985.94
toFixed(2)
ไม่เกี่ยวกับสิ่งที่ถูกต้อง แต่จะปัดเศษค่า ฉันไม่ต้องการให้ค่าถูกปัดเศษ หวังว่าสิ่งนี้จะเป็นไปได้ในจาวาสคริปต์
คำตอบ:
อัพเดต :
ดังนั้นหลังจากทั้งหมดปรากฎข้อบกพร่องการปัดเศษจะหลอกหลอนคุณเสมอไม่ว่าคุณจะพยายามชดเชยมันมากแค่ไหน ดังนั้นปัญหาควรถูกโจมตีโดยการแสดงตัวเลขในสัญกรณ์ทศนิยม
Number.prototype.toFixedDown = function(digits) {
var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"),
m = this.toString().match(re);
return m ? parseFloat(m[1]) : this.valueOf();
};
[ 5.467.toFixedDown(2),
985.943.toFixedDown(2),
17.56.toFixedDown(2),
(0).toFixedDown(1),
1.11.toFixedDown(1) + 22];
// [5.46, 985.94, 17.56, 0, 23.1]
โซลูชันเก่าที่เกิดข้อผิดพลาดขึ้นอยู่กับการรวบรวมผู้อื่น:
Number.prototype.toFixedDown = function(digits) {
var n = this - Math.pow(10, -digits)/2;
n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56"
return n.toFixed(digits);
}
1.11.toFixedDown(1) + 22
ปลายขึ้นเป็นแทน1.122
23.1
นอกจากนี้ยัง0.toFixedDown(1)
ควรผลิตแต่มันผลิต0
-0.1
(-10.2131).toFixedDown(2) // ==> 10.21
.
(1e-7).toFixedDown(0) // ==> 1e-7
. ไม่ว่าสำหรับ1e-(>=7)
(อดีต: 1e-8
, 1e-9
, ... )
คำตอบของ Dogbert นั้นดี แต่ถ้ารหัสของคุณอาจต้องจัดการกับตัวเลขติดลบMath.floor
ด้วยตัวมันเองอาจให้ผลลัพธ์ที่ไม่คาดคิด
เช่นMath.floor(4.3) = 4
แต่Math.floor(-4.3) = -5
ใช้ฟังก์ชันตัวช่วยเช่นนี้แทนเพื่อให้ได้ผลลัพธ์ที่สอดคล้องกัน:
truncateDecimals = function (number) {
return Math[number < 0 ? 'ceil' : 'floor'](number);
};
// Applied to Dogbert's answer:
var a = 5.467;
var truncated = truncateDecimals(a * 100) / 100; // = 5.46
นี่คือเวอร์ชันที่สะดวกกว่าของฟังก์ชันนี้:
truncateDecimals = function (number, digits) {
var multiplier = Math.pow(10, digits),
adjustedNum = number * multiplier,
truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum);
return truncatedNum / multiplier;
};
// Usage:
var a = 5.467;
var truncated = truncateDecimals(a, 2); // = 5.46
// Negative digits:
var b = 4235.24;
var truncated = truncateDecimals(b, -2); // = 4200
หากนั่นไม่ใช่พฤติกรรมที่ต้องการให้แทรกการโทรไปMath.abs
ที่บรรทัดแรก:
var multiplier = Math.pow(10, Math.abs(digits)),
แก้ไข: shendz อย่างถูกต้องชี้ให้เห็นว่าการใช้วิธีนี้กับไม่ถูกต้องจะผลิตa = 17.56
17.55
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุที่เกิดขึ้นนี้อ่านอะไรทุกนักวิทยาศาสตร์คอมพิวเตอร์ควรรู้เกี่ยวกับจุดลอยเลขคณิต น่าเสียดายที่การเขียนวิธีแก้ปัญหาที่กำจัดแหล่งที่มาทั้งหมดของข้อผิดพลาดทศนิยมนั้นค่อนข้างยุ่งยากด้วยจาวาสคริปต์ ในภาษาอื่นคุณจะใช้จำนวนเต็มหรืออาจจะเป็นประเภททศนิยม แต่ใช้จาวาสคริปต์ ...
โซลูชันนี้ควรมีความแม่นยำ 100% แต่จะช้าลงด้วย:
function truncateDecimals (num, digits) {
var numS = num.toString(),
decPos = numS.indexOf('.'),
substrLength = decPos == -1 ? numS.length : 1 + decPos + digits,
trimmedResult = numS.substr(0, substrLength),
finalResult = isNaN(trimmedResult) ? 0 : trimmedResult;
return parseFloat(finalResult);
}
สำหรับผู้ที่ต้องการความเร็ว แต่ยังต้องการหลีกเลี่ยงข้อผิดพลาดจุดลอยตัวลองสิ่งที่ต้องการBigDecimal.js คุณสามารถค้นหาไลบรารี javascript BigDecimal อื่น ๆ ในคำถาม SO นี้: "มีไลบรารี Javascript BigDecimal ที่ดีหรือไม่" และนี่คือบล็อกโพสต์ที่ดีเกี่ยวกับห้องสมุดคณิตศาสตร์สำหรับ Javascript
if(isNAN(result) result = 0;
ขึ้นอยู่กับพฤติกรรมที่คุณต้องการ
var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46
truncate(-3.14)
และรับ-4
กลับฉันจะเรียกสิ่งนั้นไม่พึงปรารถนาแน่นอน
var a = 65.1
var truncated = Math.floor(a * 100) / 100; // = 65.09
ดังนั้นนี่ไม่ใช่วิธีแก้ปัญหาที่ถูกต้อง
คุณสามารถแก้ไขการปัดเศษได้โดยการลบ 0.5 สำหรับ toFixed เช่น
(f - 0.005).toFixed(2)
พิจารณาใช้ประโยชน์จากเครื่องหมายตัวหนอนคู่:~~
.
รับจำนวน. คูณด้วยเลขนัยสำคัญหลังจุดทศนิยมเพื่อให้คุณสามารถตัดทอนให้เหลือศูนย์~~
ได้ หารตัวคูณนั้นกลับออกไป กำไร.
function truncator(numToTruncate, intDecimalPlaces) {
var numPower = Math.pow(10, intDecimalPlaces); // "numPowerConverter" might be better
return ~~(numToTruncate * numPower)/numPower;
}
ฉันพยายามที่จะต่อต้านการตัด~~
สายใน parens; ฉันเชื่อว่าลำดับการดำเนินงานควรทำให้ทำงานได้อย่างถูกต้อง
alert(truncator(5.1231231, 1)); // is 5.1
alert(truncator(-5.73, 1)); // is -5.7
alert(truncator(-5.73, 0)); // is -5
การเชื่อมโยง JSFiddle
แก้ไข:เมื่อมองย้อนกลับไปฉันได้จัดการกรณีโดยไม่ได้ตั้งใจให้ปัดเศษทศนิยมออกไปทางซ้ายเช่นกัน
alert(truncator(4343.123, -2)); // gives 4300.
ตรรกะแปลกประหลาดเล็กน้อยที่กำลังมองหาการใช้งานนั้นและอาจได้รับประโยชน์จาก refactor อย่างรวดเร็ว แต่ก็ยังใช้งานได้ โชคดีกว่าดี.
Math
ต้นแบบด้วยสิ่งนี้และตรวจสอบ NaN-s ก่อนที่จะดำเนินการมันจะสมบูรณ์แบบ
truncator((10 * 2.9) / 100, 2)
กลับ 0.28 แทนที่จะเป็น 0.29 ... jsfiddle.net/25tgrzq1
โซลูชันบรรทัดเดียวที่ดี:
function truncate (num, places) {
return Math.trunc(num * Math.pow(10, places)) / Math.pow(10, places);
}
จากนั้นโทรด้วย:
truncate(3.5636232, 2); // returns 3.56
truncate(5.4332312, 3); // returns 5.433
truncate(25.463214, 4); // returns 25.4632
ฉันคิดว่าฉันจะตอบโดยใช้|
เพราะมันง่ายและใช้งานได้ดี
truncate = function(number, places) {
var shift = Math.pow(10, places);
return ((number * shift) | 0) / shift;
};
or
ing ด้วย 0 หมายถึง "เก็บสิ่งที่ฉันมีอยู่แล้ว" ~~
คำตอบของฉันทำอะไร แต่ด้วยการดำเนินการแบบบิตเดียว แม้ว่าจะมีข้อ จำกัด เช่นเดียวกับที่เขียนไว้เช่นกัน: เราไม่สามารถไปมากกว่า 2 ^ 31ได้
truncate((10 * 2.9) / 100);
รหัสนี้ส่งคืน 0.28 แทนที่จะเป็น 0.29 jsfiddle.net/9pf0732d
ตัดทอนโดยใช้ตัวดำเนินการแบบบิต:
~~0.5 === 0
~~(-0.5) === 0
~~14.32794823 === 14
~~(-439.93) === -439
คำตอบของ @ Dogbert สามารถปรับปรุงได้Math.trunc
ซึ่งจะตัดทอนแทนที่จะปัดเศษ
มีความแตกต่างระหว่างการปัดเศษและการตัดทอน การตัดทอนเป็นพฤติกรรมที่คำถามนี้กำลังมองหาอย่างชัดเจน ถ้าฉันเรียกตัดทอน (-3.14) และรับ -4 กลับฉันจะเรียกสิ่งนั้นว่าไม่พึงปรารถนาแน่นอน - @NickKnowlson
var a = 5.467;
var truncated = Math.trunc(a * 100) / 100; // = 5.46
var a = -5.467;
var truncated = Math.trunc(a * 100) / 100; // = -5.46
Math.trunc
แต่แทนที่จะ9.28 * 100
เป็นมากกว่า927.9999
928
คุณอาจต้องการอ่านเรื่องThe Perils of Floating Point
ฉันเขียนคำตอบโดยใช้วิธีที่สั้นกว่า นี่คือสิ่งที่ฉันคิดขึ้นมา
function truncate(value, precision) {
var step = Math.pow(10, precision || 0);
var temp = Math.trunc(step * value);
return temp / step;
}
สามารถใช้วิธีการเช่นนั้น
truncate(132456.25456789, 5)); // Output: 132456.25456
truncate(132456.25456789, 3)); // Output: 132456.254
truncate(132456.25456789, 1)); // Output: 132456.2
truncate(132456.25456789)); // Output: 132456
หรือถ้าคุณต้องการไวยากรณ์ที่สั้นกว่านี้คุณไปเลย
function truncate(v, p) {
var s = Math.pow(10, p || 0);
return Math.trunc(s * v) / s;
}
Number.prototype.trim = function(decimals) {
var s = this.toString();
var d = s.split(".");
d[1] = d[1].substring(0, decimals);
return parseFloat(d.join("."));
}
console.log((5.676).trim(2)); //logs 5.67
ฉันคิดว่าฟังก์ชันนี้อาจเป็นวิธีง่ายๆ:
function trunc(decimal,n=2){
let x = decimal + ''; // string
return x.lastIndexOf('.')>=0?parseFloat(x.substr(0,x.lastIndexOf('.')+(n+1))):decimal; // You can use indexOf() instead of lastIndexOf()
}
console.log(trunc(-241.31234,2));
console.log(trunc(241.312,5));
console.log(trunc(-241.233));
console.log(trunc(241.2,0));
console.log(trunc(241));
ฉันพบปัญหา: พิจารณาสถานการณ์ถัดไป: 2.1 หรือ 1.2 หรือ -6.4
จะเป็นอย่างไรถ้าคุณต้องการ 3 ทศนิยมหรือสองหรือ wharever เสมอดังนั้นคุณต้องเติมเลขศูนย์นำหน้าทางด้านขวา
// 3 decimals numbers
0.5 => 0.500
// 6 decimals
0.1 => 0.10000
// 4 decimales
-2.1 => -2.1000
// truncate to 3 decimals
3.11568 => 3.115
นี่คือฟังก์ชันคงที่ของ Nick Knowlson
function truncateDecimals (num, digits)
{
var numS = num.toString();
var decPos = numS.indexOf('.');
var substrLength = decPos == -1 ? numS.length : 1 + decPos + digits;
var trimmedResult = numS.substr(0, substrLength);
var finalResult = isNaN(trimmedResult) ? 0 : trimmedResult;
// adds leading zeros to the right
if (decPos != -1){
var s = trimmedResult+"";
decPos = s.indexOf('.');
var decLength = s.length - decPos;
while (decLength <= digits){
s = s + "0";
decPos = s.indexOf('.');
decLength = s.length - decPos;
substrLength = decPos == -1 ? s.length : 1 + decPos + digits;
};
finalResult = s;
}
return finalResult;
};
x = 0.0000
การทดสอบtruncateDecimals (x, 2)
ล้มเหลว 0
ผลตอบแทน ไม่เป็นไปตามคาด0.00
function toFixed(number, digits) {
var reg_ex = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)")
var array = number.toString().match(reg_ex);
return array ? parseFloat(array[1]) : number.valueOf()
}
var test = 10.123456789
var __fixed = toFixed(test, 6)
console.log(__fixed)
// => 10.123456
คำตอบของ @kirilloid ดูเหมือนจะเป็นคำตอบที่ถูกต้องอย่างไรก็ตามต้องมีการอัปเดตรหัสหลัก วิธีแก้ปัญหาของเขาไม่ได้ดูแลตัวเลขเชิงลบ (ซึ่งมีคนพูดถึงในส่วนความคิดเห็น แต่ยังไม่ได้รับการอัปเดตในรหัสหลัก)
การอัปเดตเป็นโซลูชันการทดสอบขั้นสุดท้ายที่สมบูรณ์:
Number.prototype.toFixedDown = function(digits) {
var re = new RegExp("([-]*\\d+\\.\\d{" + digits + "})(\\d)"),
m = this.toString().match(re);
return m ? parseFloat(m[1]) : this.valueOf();
};
การใช้งานตัวอย่าง:
var x = 3.1415629;
Logger.log(x.toFixedDown(2)); //or use whatever you use to log
Fiddle: JS Number ปัดเศษลง
PS: มี repo ไม่เพียงพอที่จะแสดงความคิดเห็นเกี่ยวกับโซลูชันนั้น
นี่คือฟังก์ชั่นที่เรียบง่าย แต่ใช้งานได้เพื่อตัดทอนจำนวนทศนิยมไม่เกิน 2 ตำแหน่ง
function truncateNumber(num) {
var num1 = "";
var num2 = "";
var num1 = num.split('.')[0];
num2 = num.split('.')[1];
var decimalNum = num2.substring(0, 2);
var strNum = num1 +"."+ decimalNum;
var finalNum = parseFloat(strNum);
return finalNum;
}
ประเภทผลลัพธ์ยังคงเป็นตัวเลข ...
/* Return the truncation of n wrt base */
var trunc = function(n, base) {
n = (n / base) | 0;
return base * n;
};
var t = trunc(5.467, 0.01);
Lodash มีไม่กี่วิธีคณิตศาสตร์ยูทิลิตี้ที่สามารถรอบ , พื้นและceilจำนวนความแม่นยำทศนิยมที่กำหนด สิ่งนี้ทำให้ไม่มีศูนย์ต่อท้าย
พวกเขาใช้แนวทางที่น่าสนใจโดยใช้เลขชี้กำลังของจำนวน เห็นได้ชัดว่าสิ่งนี้หลีกเลี่ยงปัญหาการปัดเศษ
(หมายเหตุ: func
คือMath.round
หรือceil
หรือfloor
ในรหัสด้านล่าง)
// Shift with exponential notation to avoid floating-point issues.
var pair = (toString(number) + 'e').split('e'),
value = func(pair[0] + 'e' + (+pair[1] + precision));
pair = (toString(value) + 'e').split('e');
return +(pair[0] + 'e' + (+pair[1] - precision));
นี่คือสิ่งที่ฉันทำในหัวข้อ:
convert.truncate = function(value, decimals) {
decimals = (decimals === undefined ? 0 : decimals);
return parseFloat((value-(0.5/Math.pow(10, decimals))).toFixed(decimals),10);
};
เป็นเพียงเวอร์ชันที่ซับซ้อนกว่าเล็กน้อยของไฟล์
(f - 0.005).toFixed(2)
สิ่งที่ทำเครื่องหมายว่าเป็นโซลูชันคือทางออกที่ดีกว่าที่ฉันพบจนถึงวันนี้ แต่มีปัญหาร้ายแรงกับ 0 (เช่น 0.toFixedDown (2) ให้ -0.01) ดังนั้นฉันขอแนะนำให้ใช้สิ่งนี้:
Number.prototype.toFixedDown = function(digits) {
if(this == 0) {
return 0;
}
var n = this - Math.pow(10, -digits)/2;
n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56"
return n.toFixed(digits);
}
นี่คือสิ่งที่ฉันใช้:
var t = 1;
for (var i = 0; i < decimalPrecision; i++)
t = t * 10;
var f = parseFloat(value);
return (Math.floor(f * t)) / t;
const TO_FIXED_MAX = 100;
function truncate(number, decimalsPrecison) {
// make it a string with precision 1e-100
number = number.toFixed(TO_FIXED_MAX);
// chop off uneccessary digits
const dotIndex = number.indexOf('.');
number = number.substring(0, dotIndex + decimalsPrecison + 1);
// back to a number data type (app specific)
return Number.parseFloat(number);
}
// example
truncate(0.00000001999, 8);
0.00000001
ทำงานร่วมกับ:
เพียงเพื่อชี้ให้เห็นวิธีง่ายๆที่ได้ผลสำหรับฉัน
แปลงเป็นสตริงแล้ว regex ...
var number = 123.45678;
var number_s = '' + number;
var number_truncated_s = number_s.match(/\d*\.\d{4}/)[0]
var number_truncated = parseFloat(number_truncated_s)
สามารถย่อเป็น
var number_truncated = parseFloat(('' + 123.4568908).match(/\d*\.\d{4}/)[0])
นี่คือรหัส ES6 ที่ทำในสิ่งที่คุณต้องการ
const truncateTo = (unRouned, nrOfDecimals = 2) => {
const parts = String(unRouned).split(".");
if (parts.length !== 2) {
// without any decimal part
return unRouned;
}
const newDecimals = parts[1].slice(0, nrOfDecimals),
newString = `${parts[0]}.${newDecimals}`;
return Number(newString);
};
// your examples
console.log(truncateTo(5.467)); // ---> 5.46
console.log(truncateTo(985.943)); // ---> 985.94
// other examples
console.log(truncateTo(5)); // ---> 5
console.log(truncateTo(-5)); // ---> -5
console.log(truncateTo(-985.943)); // ---> -985.94
Number.prototype.truncate = function(places) {
var shift = Math.pow(10, places);
return Math.trunc(this * shift) / shift;
};
คุณสามารถทำงานกับสตริง ตรวจสอบว่า "." มีอยู่แล้วลบบางส่วนของสตริง
ตัดทอน (7.88, 1) -> 7.8
ตัดทอน (7.889, 2) -> 7.89
ตัดทอน (-7.88, 1) -> -7.88
function truncate(number, decimals) {
const tmp = number + '';
if (tmp.indexOf('.') > -1) {
return +tmp.substr(0 , tmp.indexOf('.') + decimals+1 );
} else {
return +number
}
}
ฉันสับสนเล็กน้อยว่าทำไมถึงมีคำตอบที่แตกต่างกันมากมายสำหรับคำถามง่ายๆเช่นนี้ มีเพียงสองวิธีที่ฉันเห็นซึ่งดูเหมือนจะคุ้มค่า ฉันทำการเปรียบเทียบอย่างรวดเร็วเพื่อดูความแตกต่างของความเร็วโดยใช้https://jsbench.me/ https://jsbench.me/
นี่คือคำตอบซึ่งปัจจุบัน (9/26/2020) ถูกตั้งค่าสถานะเป็นคำตอบ:
function truncate(n, digits) {
var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"),
m = n.toString().match(re);
return m ? parseFloat(m[1]) : n.valueOf();
};
[ truncate(5.467,2),
truncate(985.943,2),
truncate(17.56,2),
truncate(0, 1),
truncate(1.11, 1) + 22];
อย่างไรก็ตามนี่เป็นการทำสิ่งที่เป็นสตริงและ regex ซึ่งโดยปกติจะไม่มีประสิทธิภาพมากนักและมีฟังก์ชัน Math.trunc ที่ทำอย่างแน่นอนที่ OP ต้องการโดยไม่มีทศนิยม ดังนั้นคุณสามารถใช้มันบวกเลขคณิตพิเศษเล็กน้อยเพื่อให้ได้สิ่งเดียวกัน
นี่เป็นอีกวิธีหนึ่งที่ฉันพบในเธรดนี้ซึ่งเป็นวิธีที่ฉันจะใช้:
function truncate(n, digits) {
var step = Math.pow(10, digits || 0);
var temp = Math.trunc(step * n);
return temp / step;
}
[ truncate(5.467,2),
truncate(985.943,2),
truncate(17.56,2),
truncate(0, 1),
truncate(1.11, 1) + 22];
วิธีแรกช้ากว่าวิธีที่สอง 99.92% ดังนั้นวิธีที่สองแน่นอนหนึ่งที่ผมจะแนะนำให้ใช้
เอาล่ะกลับไปหาวิธีเลี่ยงงานอื่น ...