为什么 JavaScript base-36 转换看起来不明确
Why JavaScript base-36 conversion appears to be ambiguous
我目前正在写一篇使用 base 36 编码的 JavaScript。
我遇到了这个问题:
parseInt("welcomeback",36).toString(36)
似乎 return "welcomebacg"
。
我在 Chrome 开发人员控制台和 Node.js 中测试了这个,结果相同。
这个结果有什么合乎逻辑的解释吗?
JavaScript中的数字数据类型是64位浮点数,它可以安全地表示最大为2^53-1的整数,参见What is JavaScript's highest integer value that a number can go to without losing precision?
parseInt("welcomeback",36)
的结果超出了该限制。结果将是最接近可以表示的数字。
一个 JS Number 可以安全地容纳 10 个 base-36 数字,因此将其解析为 BigInt 的一种有效方法是将字符串拆分为 10 个数字的块,然后将它们组合起来。其他答案显示了使用 reduce
的类似技术,这里是使用 forEach
:
function toBigInt36(str) {
const multiplier = BigInt(Math.pow(36, 10));
const chunks = str.match(/.{1,10}/g);
let result = BigInt(0);
chunks.forEach((chunk) => {
result = result * multiplier + BigInt(parseInt(chunk, 36))
});
return result;
}
parseInt("welcomeback",36)
的结果手动大于 Number.MAX_SAFE_INTEGER
(253-1) and thus cannot be accurately represented. A possible workaround is to perform base conversion with BigInt
。
const str = "welcomeback";
const base = 36;
const res = [...str].reduce((acc,curr)=>
BigInt(parseInt(curr, base)) + BigInt(base) * acc, 0n);
console.log(res.toString());
console.log(res.toString(36));
我目前正在写一篇使用 base 36 编码的 JavaScript。
我遇到了这个问题:
parseInt("welcomeback",36).toString(36)
似乎 return "welcomebacg"
。
我在 Chrome 开发人员控制台和 Node.js 中测试了这个,结果相同。
这个结果有什么合乎逻辑的解释吗?
JavaScript中的数字数据类型是64位浮点数,它可以安全地表示最大为2^53-1的整数,参见What is JavaScript's highest integer value that a number can go to without losing precision?
parseInt("welcomeback",36)
的结果超出了该限制。结果将是最接近可以表示的数字。
一个 JS Number 可以安全地容纳 10 个 base-36 数字,因此将其解析为 BigInt 的一种有效方法是将字符串拆分为 10 个数字的块,然后将它们组合起来。其他答案显示了使用 reduce
的类似技术,这里是使用 forEach
:
function toBigInt36(str) {
const multiplier = BigInt(Math.pow(36, 10));
const chunks = str.match(/.{1,10}/g);
let result = BigInt(0);
chunks.forEach((chunk) => {
result = result * multiplier + BigInt(parseInt(chunk, 36))
});
return result;
}
parseInt("welcomeback",36)
的结果手动大于 Number.MAX_SAFE_INTEGER
(253-1) and thus cannot be accurately represented. A possible workaround is to perform base conversion with BigInt
。
const str = "welcomeback";
const base = 36;
const res = [...str].reduce((acc,curr)=>
BigInt(parseInt(curr, base)) + BigInt(base) * acc, 0n);
console.log(res.toString());
console.log(res.toString(36));