你如何在 JavaScript 中以 10 以外的基数取整一个数字?

Ste*_*ies 7 javascript base rounding

例如,假设我有一个12.24以 8 为基数(10.3125以 10 为基数)的数字,我想将该数字四舍五入到 1 个精度点,以便得到12.3.

Ale*_*Sp3 3

解决方案1

\n
    \n
  • js 中没有\xc2\xb4t 函数可以做到这一点。因此需要创建一个才能做到这一点。它的作用是检查要修复的数字(在您的情况下为“4”)是否更接近基数(8)或更接近0:

    \n
    if (base - digit_tofix <= base / 2) {\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
\n

然后,只需将差值加或减为 10 或 0,因此如果数字为12.24,则会返回:

\n
return 12.24 + 0.06;   // ---> equals to 12.3\n
Run Code Online (Sandbox Code Playgroud)\n

如果数字为 12.23,则返回:

\n
return 12.23 - 0.03    // ---> equals to 12.2\n
Run Code Online (Sandbox Code Playgroud)\n

所以可以做这样的事情:

\n
function round(n, base, precision) {\n  const digit_tofix = n.toString().split(".")[1].split("")[precision];\n  if (base - digit_tofix <= base / 2) {\n    return (n + (10 - digit_tofix) / Math.pow(10, precision + 1)).toFixed(precision);\n  }else {\n    return (n - digit_tofix / Math.pow(10, precision + 1)).toFixed(precision);\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

编辑:但是,这不会\xc2\xb4t 捕获进位溢出。所以base_8中的数字如下所示:

\n
55.74\n
Run Code Online (Sandbox Code Playgroud)\n

将转变为:

\n
55.74 + 0.06 = 55.8   // --> number 8 doesn\xc2\xb4t exist in octal\n
Run Code Online (Sandbox Code Playgroud)\n

所以必须有一个使用的溢出检查循环do while()。该语句的作用是将 移至digit_tofix前一个数字,并在每次相加时检查是否存在溢出:

\n
// Overflow check\ndo {\n    n += (10 - digit_tofix) / Math.pow(10, precision + 1);\n    precision--;\n    digit_tofix = precision > -1 ? n.toFixed(precision + 1).split(".")[1].split("")[precision] :\n                                   n.toFixed(0).split(".")[0].split("")[precision + n.toString().split(".")[0].split("").length];\n} while(digit_tofix == base);\n    \nreturn n.toFixed(precision > -1 ? precision + 1 : 0);\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  • 它适用于任何 10 以内的基数(不是十六进制,因为包含字母)和任何您想要的精度,只需更改函数中的参数即可round()。这里有一些工作示例
  • \n
\n

八进制

\n

\r\n
\r\n
if (base - digit_tofix <= base / 2) {\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

二进制

\n

\r\n
\r\n
return 12.24 + 0.06;   // ---> equals to 12.3\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n


\n

解决方案2

\n
function round(n, base, precision) {\n  // To get number value of letter: a = 10, b = 11, c = 12 ...\n  const getNumber = e => isNaN(e) ? e.charCodeAt(0) - 87 : parseInt(e);\n\n  // Just to check incompability and invalid parameters\n  const checkIncompatible = () => {\n    if (digits.reduce((a, d) => d == "." ? ++a : a, 0) > 1 || \n        (digits.some(d => isNaN(d) && (getNumber(d) < 10 || getNumber(d) > 35) && d != ".")))   return "Invalid Number";\n    if (digits.some(d => getNumber(d) >= base  && d != "."))    return "Number doesn\xc2\xb4t match base";\n    if (precision < 0)  return "Invalid precision argument";\n    if (base < 2 || base > 36)  return "Invalid base argument";\n    return false;\n  };\n  \n  // Recursive function to carry overflow\n  const add = p => {\n    if (digits[p] == ".") add(p - 1);\n    else if (getNumber(digits[p]) + 1 == base) {\n      digits[p] = "0";\n      if (p > 0)    add(p - 1);\n      else digits.unshift("1");\n    }else {\n      if (isNaN(digits[p])) digits[p] = String.fromCharCode(digits[p].charCodeAt(0) + 1);\n      else digits[p] = digits[p] < 9 ? parseInt(digits[p]) + 1 : "a" ;\n    }\n  };\n  \n  n = n.toString().toLowerCase().split(",").join(".");  // In case there is a comma\n  let digits = n.split("");\n\n  // Avoid problems with undefined array index and other issues\n  if (typeof digits[digits.indexOf(".") + 1 + precision] === "undefined" ||\n      digits.reduce((a, d) => d == "." ? ++a : a, 0) < 1)   return n;\n  let state = checkIncompatible();\n  if (state) return state;\n\n  const digit_tofix = getNumber(digits[digits.indexOf(".") + 1 + precision]);\n\n  // Check if digit_tofix is closer to base or zero\n  if (base - digit_tofix <= base / 2) {\n   add(digits.indexOf(".") + precision);\n  }\n\n  // Splice the array to get the substring\n  digits.splice(digits.indexOf(".") + 1 + precision);\n  if (!precision) digits.splice(-1);\n  return digits.join("");\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这个解决方案更复杂,但更广泛,因为您可以使用从 2 到 36 的任何数字,这意味着您可以使用十六进制。

\n

与第一个解决方案类似,它检查要修复的数字(在您的情况下为“4”)是否更接近基数(8)或更接近0:

\n
if (base - digit_tofix <= base / 2) {\n
Run Code Online (Sandbox Code Playgroud)\n

如果接近于零,只需取数字的子串(使用splice()数组方法)。所以如果数字是:

\n
"12.23"\n
Run Code Online (Sandbox Code Playgroud)\n

它的子串是

\n
"12.2"\n
Run Code Online (Sandbox Code Playgroud)\n

但是如果要固定的数字更接近基数,我们需要在前一个数字上加+1 ,所以如果数字是:

\n
"12.24"\n
Run Code Online (Sandbox Code Playgroud)\n

它的子串是

\n
"12.3"    //--> 2 + 1 = 3\n
Run Code Online (Sandbox Code Playgroud)\n

特别案例

\n

例如,如果base_8中的数字是:

\n
"12.74"\n
Run Code Online (Sandbox Code Playgroud)\n

它的子串应该是

\n
"13.0"    // 7 + 1 = 8 (base is 8 so there is an overflow)\n
Run Code Online (Sandbox Code Playgroud)\n

这就是为什么要调用一个递归函数add()以便在溢出时进行进位。

\n

该round()函数返回一个包含新数字的字符串。

\n

尝试解决方案

\n

十六进制

\n

\r\n
\r\n
return 12.23 - 0.03    // ---> equals to 12.2\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

八进制

\n

\r\n
\r\n
function round(n, base, precision) {\n  const digit_tofix = n.toString().split(".")[1].split("")[precision];\n  if (base - digit_tofix <= base / 2) {\n    return (n + (10 - digit_tofix) / Math.pow(10, precision + 1)).toFixed(precision);\n  }else {\n    return (n - digit_tofix / Math.pow(10, precision + 1)).toFixed(precision);\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

二进制

\n

\r\n

\n