如何以 10 以外的基数对 JavaScript 中的数字进行四舍五入?
How do you round a number in JavaScript in a base other than 10?
例如,假设我有一个以 8 为底的数字 12.24
(以 10 为底的 10.3125
),我想将该数字四舍五入到 1 点精度,以便我得到 12.3
.
解决方案 1
js 中没有可以做到这一点的函数。所以需要创建一个才能做到这一点。它的作用是检查要修复的数字(在您的情况下为“4”)是否更接近基数 (8) 或更接近 0:
if (base - digit_tofix <= base / 2) {
然后,只需将差值加或减到 10 或 0,所以如果数字是 12.24
,它会 return:
return 12.24 + 0.06; // ---> equals to 12.3
如果号码是12.23
,returns:
return 12.23 - 0.03 // ---> equals to 12.2
所以可以做这样的东西:
function round(n, base, precision) {
const digit_tofix = n.toString().split(".")[1].split("")[precision];
if (base - digit_tofix <= base / 2) {
return (n + (10 - digit_tofix) / Math.pow(10, precision + 1)).toFixed(precision);
}else {
return (n - digit_tofix / Math.pow(10, precision + 1)).toFixed(precision);
}
}
编辑: 但是,这不会捕获 进位溢出 。所以 base_8 中的数字是这样的:
55.74
将转换为:
55.74 + 0.06 = 55.8 // --> number 8 doesn´t exist in octal
所以必须有一个溢出检查循环使用do while()
。这条语句的作用是将digit_tofix
移动到之前的数字,每次加法检查是否溢出:
// Overflow check
do {
n += (10 - digit_tofix) / Math.pow(10, precision + 1);
precision--;
digit_tofix = precision > -1 ? n.toFixed(precision + 1).split(".")[1].split("")[precision] :
n.toFixed(0).split(".")[0].split("")[precision + n.toString().split(".")[0].split("").length];
} while(digit_tofix == base);
return n.toFixed(precision > -1 ? precision + 1 : 0);
- 它适用于最多 10 的任何基数(不是十六进制,因为包含字母)和您想要的任何精度,只需更改
round()
函数中的参数即可。这里有一些工作示例
八进制
const oct = 12.24;
console.log( round(oct, 8, 1) );
function round(n, base, precision) {
let digit_tofix = n.toString().split(".")[1].split("")[precision];
if (base - digit_tofix <= base / 2) {
// Overflow check
do {
n += (10 - digit_tofix) / Math.pow(10, precision + 1);
precision--;
digit_tofix = precision > -1 ? n.toFixed(precision + 1).split(".")[1].split("")[precision] :
n.toFixed(0).split(".")[0].split("")[precision + n.toString().split(".")[0].split("").length];
} while(digit_tofix == base);
return n.toFixed(precision > -1 ? precision + 1 : 0);
}else {
return (n - digit_tofix / Math.pow(10, precision + 1)).toFixed(precision);
}
}
二进制
const bin = 10011.011;
console.log( round(bin, 2, 1) );
function round(n, base, precision) {
let digit_tofix = n.toString().split(".")[1].split("")[precision];
if (base - digit_tofix <= base / 2) {
// Overflow check
do {
n += (10 - digit_tofix) / Math.pow(10, precision + 1);
precision--;
digit_tofix = precision > -1 ? n.toFixed(precision + 1).split(".")[1].split("")[precision] :
n.toFixed(0).split(".")[0].split("")[precision + n.toString().split(".")[0].split("").length];
} while(digit_tofix == base);
return n.toFixed(precision > -1 ? precision + 1 : 0);
}else {
return (n - digit_tofix / Math.pow(10, precision + 1)).toFixed(precision);
}
}
解决方案 2
function round(n, base, precision) {
// To get number value of letter: a = 10, b = 11, c = 12 ...
const getNumber = e => isNaN(e) ? e.charCodeAt(0) - 87 : parseInt(e);
// Just to check incompability and invalid parameters
const checkIncompatible = () => {
if (digits.reduce((a, d) => d == "." ? ++a : a, 0) > 1 ||
(digits.some(d => isNaN(d) && (getNumber(d) < 10 || getNumber(d) > 35) && d != "."))) return "Invalid Number";
if (digits.some(d => getNumber(d) >= base && d != ".")) return "Number doesn´t match base";
if (precision < 0) return "Invalid precision argument";
if (base < 2 || base > 36) return "Invalid base argument";
return false;
};
// Recursive function to carry overflow
const add = p => {
if (digits[p] == ".") add(p - 1);
else if (getNumber(digits[p]) + 1 == base) {
digits[p] = "0";
if (p > 0) add(p - 1);
else digits.unshift("1");
}else {
if (isNaN(digits[p])) digits[p] = String.fromCharCode(digits[p].charCodeAt(0) + 1);
else digits[p] = digits[p] < 9 ? parseInt(digits[p]) + 1 : "a" ;
}
};
n = n.toString().toLowerCase().split(",").join("."); // In case there is a comma
let digits = n.split("");
// Avoid problems with undefined array index and other issues
if (typeof digits[digits.indexOf(".") + 1 + precision] === "undefined" ||
digits.reduce((a, d) => d == "." ? ++a : a, 0) < 1) return n;
let state = checkIncompatible();
if (state) return state;
const digit_tofix = getNumber(digits[digits.indexOf(".") + 1 + precision]);
// Check if digit_tofix is closer to base or zero
if (base - digit_tofix <= base / 2) {
add(digits.indexOf(".") + precision);
}
// Splice the array to get the substring
digits.splice(digits.indexOf(".") + 1 + precision);
if (!precision) digits.splice(-1);
return digits.join("");
}
此解决方案更复杂,但范围更广,因为您可以使用从 2 到 36 的任何数字,这意味着您可以使用十六进制。
与第一个解决方案类似,它检查要修复的数字(在您的情况下为“4”)是更接近基数 (8) 还是更接近 0:
if (base - digit_tofix <= base / 2) {
如果接近零,只需要取数字的子串即可(使用splice()
数组法)。所以如果数字是:
"12.23"
它的子串是
"12.2"
但是如果digit-to-fix更接近base,我们需要在前面的数字上加上+1,所以如果数字是:
"12.24"
它的子串是
"12.3" //--> 2 + 1 = 3
特例
例如,如果 base_8 中的数字是:
"12.74"
它的子串应该是
"13.0" // 7 + 1 = 8 (base is 8 so there is an overflow)
这就是为什么有一个称为 add()
的递归函数,以便在溢出的情况下执行。
round()
函数 return 是一个带有新数字的字符串。
尝试解决方案
十六进制
console.log( round("c3.bf9", 16, 2) );
console.log( round("AA.D1", 16, 1) );
console.log( round("ff.fff", 16, 0) );
function round(n, base, precision) {
const getNumber = e => isNaN(e) ? e.charCodeAt(0) - 87 : parseInt(e);
const checkIncompatible = () => {
if (digits.reduce((a, d) => d == "." ? ++a : a, 0) > 1 ||
(digits.some(d => isNaN(d) && (getNumber(d) < 10 || getNumber(d) > 35) && d != "."))) return "Invalid Number";
if (digits.some(d => getNumber(d) >= base && d != ".")) return "Number doesn´t match base";
if (precision < 0) return "Invalid precision argument";
if (base < 2 || base > 36) return "Invalid base argument";
return false;
};
const add = p => {
if (digits[p] == ".") add(p - 1);
else if (getNumber(digits[p]) + 1 == base) {
digits[p] = "0";
if (p > 0) add(p - 1);
else digits.unshift("1");
}else {
if (isNaN(digits[p])) digits[p] = String.fromCharCode(digits[p].charCodeAt(0) + 1);
else digits[p] = digits[p] < 9 ? parseInt(digits[p]) + 1 : "a" ;
}
};
n = n.toString().toLowerCase().split(",").join(".");
let digits = n.split("");
if (typeof digits[digits.indexOf(".") + 1 + precision] === "undefined" ||
digits.reduce((a, d) => d == "." ? ++a : a, 0) < 1) return n;
let state = checkIncompatible();
if (state) return state;
const digit_tofix = getNumber(digits[digits.indexOf(".") + 1 + precision]);
if (base - digit_tofix <= base / 2) {
add(digits.indexOf(".") + precision);
}
digits.splice(digits.indexOf(".") + 1 + precision);
if (!precision) digits.splice(-1);
return digits.join("");
}
八进制
console.log( round(12.24, 8, 1) );
console.log( round(17.77, 8, 1) );
console.log( round(0.74, 8, 1) );
function round(n, base, precision) {
const getNumber = e => isNaN(e) ? e.charCodeAt(0) - 87 : parseInt(e);
const checkIncompatible = () => {
if (digits.reduce((a, d) => d == "." ? ++a : a, 0) > 1 ||
(digits.some(d => isNaN(d) && (getNumber(d) < 10 || getNumber(d) > 35) && d != "."))) return "Invalid Number";
if (digits.some(d => getNumber(d) >= base && d != ".")) return "Number doesn´t match base";
if (precision < 0) return "Invalid precision argument";
if (base < 2 || base > 36) return "Invalid base argument";
return false;
};
const add = p => {
if (digits[p] == ".") add(p - 1);
else if (getNumber(digits[p]) + 1 == base) {
digits[p] = "0";
if (p > 0) add(p - 1);
else digits.unshift("1");
}else {
if (isNaN(digits[p])) digits[p] = String.fromCharCode(digits[p].charCodeAt(0) + 1);
else digits[p] = digits[p] < 9 ? parseInt(digits[p]) + 1 : "a" ;
}
};
n = n.toString().toLowerCase().split(",").join(".");
let digits = n.split("");
if (typeof digits[digits.indexOf(".") + 1 + precision] === "undefined" ||
digits.reduce((a, d) => d == "." ? ++a : a, 0) < 1) return n;
let state = checkIncompatible();
if (state) return state;
const digit_tofix = getNumber(digits[digits.indexOf(".") + 1 + precision]);
if (base - digit_tofix <= base / 2) {
add(digits.indexOf(".") + precision);
}
digits.splice(digits.indexOf(".") + 1 + precision);
if (!precision) digits.splice(-1);
return digits.join("");
}
二进制
console.log( round(101.10, 2, 1) );
console.log( round("100,11", 2, 1) );
console.log( round(100.11, 2, 1) );
function round(n, base, precision) {
const getNumber = e => isNaN(e) ? e.charCodeAt(0) - 87 : parseInt(e);
const checkIncompatible = () => {
if (digits.reduce((a, d) => d == "." ? ++a : a, 0) > 1 ||
(digits.some(d => isNaN(d) && (getNumber(d) < 10 || getNumber(d) > 35) && d != "."))) return "Invalid Number";
if (digits.some(d => getNumber(d) >= base && d != ".")) return "Number doesn´t match base";
if (precision < 0) return "Invalid precision argument";
if (base < 2 || base > 36) return "Invalid base argument";
return false;
};
const add = p => {
if (digits[p] == ".") add(p - 1);
else if (getNumber(digits[p]) + 1 == base) {
digits[p] = "0";
if (p > 0) add(p - 1);
else digits.unshift("1");
}else {
if (isNaN(digits[p])) digits[p] = String.fromCharCode(digits[p].charCodeAt(0) + 1);
else digits[p] = digits[p] < 9 ? parseInt(digits[p]) + 1 : "a" ;
}
};
n = n.toString().toLowerCase().split(",").join(".");
let digits = n.split("");
if (typeof digits[digits.indexOf(".") + 1 + precision] === "undefined" ||
digits.reduce((a, d) => d == "." ? ++a : a, 0) < 1) return n;
let state = checkIncompatible();
if (state) return state;
const digit_tofix = getNumber(digits[digits.indexOf(".") + 1 + precision]);
if (base - digit_tofix <= base / 2) {
add(digits.indexOf(".") + precision);
}
digits.splice(digits.indexOf(".") + 1 + precision);
if (!precision) digits.splice(-1);
return digits.join("");
}
例如,假设我有一个以 8 为底的数字 12.24
(以 10 为底的 10.3125
),我想将该数字四舍五入到 1 点精度,以便我得到 12.3
.
解决方案 1
js 中没有可以做到这一点的函数。所以需要创建一个才能做到这一点。它的作用是检查要修复的数字(在您的情况下为“4”)是否更接近基数 (8) 或更接近 0:
if (base - digit_tofix <= base / 2) {
然后,只需将差值加或减到 10 或 0,所以如果数字是 12.24
,它会 return:
return 12.24 + 0.06; // ---> equals to 12.3
如果号码是12.23
,returns:
return 12.23 - 0.03 // ---> equals to 12.2
所以可以做这样的东西:
function round(n, base, precision) {
const digit_tofix = n.toString().split(".")[1].split("")[precision];
if (base - digit_tofix <= base / 2) {
return (n + (10 - digit_tofix) / Math.pow(10, precision + 1)).toFixed(precision);
}else {
return (n - digit_tofix / Math.pow(10, precision + 1)).toFixed(precision);
}
}
编辑: 但是,这不会捕获 进位溢出 。所以 base_8 中的数字是这样的:
55.74
将转换为:
55.74 + 0.06 = 55.8 // --> number 8 doesn´t exist in octal
所以必须有一个溢出检查循环使用do while()
。这条语句的作用是将digit_tofix
移动到之前的数字,每次加法检查是否溢出:
// Overflow check
do {
n += (10 - digit_tofix) / Math.pow(10, precision + 1);
precision--;
digit_tofix = precision > -1 ? n.toFixed(precision + 1).split(".")[1].split("")[precision] :
n.toFixed(0).split(".")[0].split("")[precision + n.toString().split(".")[0].split("").length];
} while(digit_tofix == base);
return n.toFixed(precision > -1 ? precision + 1 : 0);
- 它适用于最多 10 的任何基数(不是十六进制,因为包含字母)和您想要的任何精度,只需更改
round()
函数中的参数即可。这里有一些工作示例
八进制
const oct = 12.24;
console.log( round(oct, 8, 1) );
function round(n, base, precision) {
let digit_tofix = n.toString().split(".")[1].split("")[precision];
if (base - digit_tofix <= base / 2) {
// Overflow check
do {
n += (10 - digit_tofix) / Math.pow(10, precision + 1);
precision--;
digit_tofix = precision > -1 ? n.toFixed(precision + 1).split(".")[1].split("")[precision] :
n.toFixed(0).split(".")[0].split("")[precision + n.toString().split(".")[0].split("").length];
} while(digit_tofix == base);
return n.toFixed(precision > -1 ? precision + 1 : 0);
}else {
return (n - digit_tofix / Math.pow(10, precision + 1)).toFixed(precision);
}
}
二进制
const bin = 10011.011;
console.log( round(bin, 2, 1) );
function round(n, base, precision) {
let digit_tofix = n.toString().split(".")[1].split("")[precision];
if (base - digit_tofix <= base / 2) {
// Overflow check
do {
n += (10 - digit_tofix) / Math.pow(10, precision + 1);
precision--;
digit_tofix = precision > -1 ? n.toFixed(precision + 1).split(".")[1].split("")[precision] :
n.toFixed(0).split(".")[0].split("")[precision + n.toString().split(".")[0].split("").length];
} while(digit_tofix == base);
return n.toFixed(precision > -1 ? precision + 1 : 0);
}else {
return (n - digit_tofix / Math.pow(10, precision + 1)).toFixed(precision);
}
}
解决方案 2
function round(n, base, precision) {
// To get number value of letter: a = 10, b = 11, c = 12 ...
const getNumber = e => isNaN(e) ? e.charCodeAt(0) - 87 : parseInt(e);
// Just to check incompability and invalid parameters
const checkIncompatible = () => {
if (digits.reduce((a, d) => d == "." ? ++a : a, 0) > 1 ||
(digits.some(d => isNaN(d) && (getNumber(d) < 10 || getNumber(d) > 35) && d != "."))) return "Invalid Number";
if (digits.some(d => getNumber(d) >= base && d != ".")) return "Number doesn´t match base";
if (precision < 0) return "Invalid precision argument";
if (base < 2 || base > 36) return "Invalid base argument";
return false;
};
// Recursive function to carry overflow
const add = p => {
if (digits[p] == ".") add(p - 1);
else if (getNumber(digits[p]) + 1 == base) {
digits[p] = "0";
if (p > 0) add(p - 1);
else digits.unshift("1");
}else {
if (isNaN(digits[p])) digits[p] = String.fromCharCode(digits[p].charCodeAt(0) + 1);
else digits[p] = digits[p] < 9 ? parseInt(digits[p]) + 1 : "a" ;
}
};
n = n.toString().toLowerCase().split(",").join("."); // In case there is a comma
let digits = n.split("");
// Avoid problems with undefined array index and other issues
if (typeof digits[digits.indexOf(".") + 1 + precision] === "undefined" ||
digits.reduce((a, d) => d == "." ? ++a : a, 0) < 1) return n;
let state = checkIncompatible();
if (state) return state;
const digit_tofix = getNumber(digits[digits.indexOf(".") + 1 + precision]);
// Check if digit_tofix is closer to base or zero
if (base - digit_tofix <= base / 2) {
add(digits.indexOf(".") + precision);
}
// Splice the array to get the substring
digits.splice(digits.indexOf(".") + 1 + precision);
if (!precision) digits.splice(-1);
return digits.join("");
}
此解决方案更复杂,但范围更广,因为您可以使用从 2 到 36 的任何数字,这意味着您可以使用十六进制。
与第一个解决方案类似,它检查要修复的数字(在您的情况下为“4”)是更接近基数 (8) 还是更接近 0:
if (base - digit_tofix <= base / 2) {
如果接近零,只需要取数字的子串即可(使用splice()
数组法)。所以如果数字是:
"12.23"
它的子串是
"12.2"
但是如果digit-to-fix更接近base,我们需要在前面的数字上加上+1,所以如果数字是:
"12.24"
它的子串是
"12.3" //--> 2 + 1 = 3
特例
例如,如果 base_8 中的数字是:
"12.74"
它的子串应该是
"13.0" // 7 + 1 = 8 (base is 8 so there is an overflow)
这就是为什么有一个称为 add()
的递归函数,以便在溢出的情况下执行。
round()
函数 return 是一个带有新数字的字符串。
尝试解决方案
十六进制
console.log( round("c3.bf9", 16, 2) );
console.log( round("AA.D1", 16, 1) );
console.log( round("ff.fff", 16, 0) );
function round(n, base, precision) {
const getNumber = e => isNaN(e) ? e.charCodeAt(0) - 87 : parseInt(e);
const checkIncompatible = () => {
if (digits.reduce((a, d) => d == "." ? ++a : a, 0) > 1 ||
(digits.some(d => isNaN(d) && (getNumber(d) < 10 || getNumber(d) > 35) && d != "."))) return "Invalid Number";
if (digits.some(d => getNumber(d) >= base && d != ".")) return "Number doesn´t match base";
if (precision < 0) return "Invalid precision argument";
if (base < 2 || base > 36) return "Invalid base argument";
return false;
};
const add = p => {
if (digits[p] == ".") add(p - 1);
else if (getNumber(digits[p]) + 1 == base) {
digits[p] = "0";
if (p > 0) add(p - 1);
else digits.unshift("1");
}else {
if (isNaN(digits[p])) digits[p] = String.fromCharCode(digits[p].charCodeAt(0) + 1);
else digits[p] = digits[p] < 9 ? parseInt(digits[p]) + 1 : "a" ;
}
};
n = n.toString().toLowerCase().split(",").join(".");
let digits = n.split("");
if (typeof digits[digits.indexOf(".") + 1 + precision] === "undefined" ||
digits.reduce((a, d) => d == "." ? ++a : a, 0) < 1) return n;
let state = checkIncompatible();
if (state) return state;
const digit_tofix = getNumber(digits[digits.indexOf(".") + 1 + precision]);
if (base - digit_tofix <= base / 2) {
add(digits.indexOf(".") + precision);
}
digits.splice(digits.indexOf(".") + 1 + precision);
if (!precision) digits.splice(-1);
return digits.join("");
}
八进制
console.log( round(12.24, 8, 1) );
console.log( round(17.77, 8, 1) );
console.log( round(0.74, 8, 1) );
function round(n, base, precision) {
const getNumber = e => isNaN(e) ? e.charCodeAt(0) - 87 : parseInt(e);
const checkIncompatible = () => {
if (digits.reduce((a, d) => d == "." ? ++a : a, 0) > 1 ||
(digits.some(d => isNaN(d) && (getNumber(d) < 10 || getNumber(d) > 35) && d != "."))) return "Invalid Number";
if (digits.some(d => getNumber(d) >= base && d != ".")) return "Number doesn´t match base";
if (precision < 0) return "Invalid precision argument";
if (base < 2 || base > 36) return "Invalid base argument";
return false;
};
const add = p => {
if (digits[p] == ".") add(p - 1);
else if (getNumber(digits[p]) + 1 == base) {
digits[p] = "0";
if (p > 0) add(p - 1);
else digits.unshift("1");
}else {
if (isNaN(digits[p])) digits[p] = String.fromCharCode(digits[p].charCodeAt(0) + 1);
else digits[p] = digits[p] < 9 ? parseInt(digits[p]) + 1 : "a" ;
}
};
n = n.toString().toLowerCase().split(",").join(".");
let digits = n.split("");
if (typeof digits[digits.indexOf(".") + 1 + precision] === "undefined" ||
digits.reduce((a, d) => d == "." ? ++a : a, 0) < 1) return n;
let state = checkIncompatible();
if (state) return state;
const digit_tofix = getNumber(digits[digits.indexOf(".") + 1 + precision]);
if (base - digit_tofix <= base / 2) {
add(digits.indexOf(".") + precision);
}
digits.splice(digits.indexOf(".") + 1 + precision);
if (!precision) digits.splice(-1);
return digits.join("");
}
二进制
console.log( round(101.10, 2, 1) );
console.log( round("100,11", 2, 1) );
console.log( round(100.11, 2, 1) );
function round(n, base, precision) {
const getNumber = e => isNaN(e) ? e.charCodeAt(0) - 87 : parseInt(e);
const checkIncompatible = () => {
if (digits.reduce((a, d) => d == "." ? ++a : a, 0) > 1 ||
(digits.some(d => isNaN(d) && (getNumber(d) < 10 || getNumber(d) > 35) && d != "."))) return "Invalid Number";
if (digits.some(d => getNumber(d) >= base && d != ".")) return "Number doesn´t match base";
if (precision < 0) return "Invalid precision argument";
if (base < 2 || base > 36) return "Invalid base argument";
return false;
};
const add = p => {
if (digits[p] == ".") add(p - 1);
else if (getNumber(digits[p]) + 1 == base) {
digits[p] = "0";
if (p > 0) add(p - 1);
else digits.unshift("1");
}else {
if (isNaN(digits[p])) digits[p] = String.fromCharCode(digits[p].charCodeAt(0) + 1);
else digits[p] = digits[p] < 9 ? parseInt(digits[p]) + 1 : "a" ;
}
};
n = n.toString().toLowerCase().split(",").join(".");
let digits = n.split("");
if (typeof digits[digits.indexOf(".") + 1 + precision] === "undefined" ||
digits.reduce((a, d) => d == "." ? ++a : a, 0) < 1) return n;
let state = checkIncompatible();
if (state) return state;
const digit_tofix = getNumber(digits[digits.indexOf(".") + 1 + precision]);
if (base - digit_tofix <= base / 2) {
add(digits.indexOf(".") + precision);
}
digits.splice(digits.indexOf(".") + 1 + precision);
if (!precision) digits.splice(-1);
return digits.join("");
}