JavaScript数字比应该的复杂得多

在作为开发人员工作时,有时您可能会获得需要做一些不寻常的事情或要获取信息的任务,或者为了了解而只想知道一些事情。 这些任务中有些可能很简单,有些则可能不简单。 但是可能看起来任务很简单,但是如果您不够谨慎的话,还有一些陷阱要咬住您。

在这篇简短的文章中,我想与我分享其中一种看似简单的解决方案的经验,但是实际上,这种解决方案并不能在所有情况下都给出正确的结果。

问题很简单: 确定一个数字中有多少个数字 。 这似乎不太复杂,对吧? 许多JavaScript对象都有.length 属性可以轻松确定对象的长度。 唯一的问题是Number对象没有.length 属性! 但是也许我们可以将数字转换为具有该属性的另一个对象,以便随后可以使用它来计算初始数字中的位数? 这似乎是一个很好的起点,所以让我们尝试一下。

注意:为简单起见,我们将只处理正整数。 主要思想是保留负数和浮点数,但是实现将需要更多条件和检查。

当我们看数字时,它只是一串数字。 因此,尝试将数字转换为字符串是有意义的,幸运的是,字符串的.length.length 该属性使我们可以获取字符串中的字符数。 这似乎是一个解决方案,这就是我们想要的! 让我们尝试一下。

  常数= 12345;  //很明显有五个数字 
const numberString = number.toString(); //现在是字符串'12345'

//现在记录字符串长度
console.log(numberString.length);

// 5->如预期的那样,此字符串中有五个字符,占数字的五位数

确实有效,我们很高兴解决了这一任务。 让我们再玩一些数字以确保它能正常工作。

  const number1 = 1234567890; 
const number1String = number1.toString();
console.log(number1String.length); // 10->有效

const number2 = 123456789000000;
const number2String = number2.toString();
console.log(number2String.length); // 15->不错,仍然可以使用

const number3 = 1234567890000000000;
const number3String = number3.toString();
console.log(number3String.length); // 19->不错,即使我们已经传递Number.MAX_SAFE_INTEGER值,它仍然可以使用

到目前为止,这看起来确实不错。 让我们给它一些很大的数目,只是为了好玩。

  const number4 = 12345678900000000000000000000000000000000000000; 
const number4String = number4.toString();
console.log(number4String.length); // 14->仍然很棒。...等等! 什么? 十四!?

哎呀! 应该是41,但结果是14。像往常一样,当您以为自己解决了问题时,偶然发现了一个破坏解决方案的案例。 🙁

是时候进行调试了。

由于某种原因.length number4String属性 变量返回14,而不是我们预期的41。 这意味着即使数字有41位数字,字符串也只有14个字符。 为了看看数字4的字符串表示发生了number4 变量,我们可以简单地记录该字符串表示形式并查看其外观。 实际上,让我们记录所有先前的记录,以便我们可以进行比较。

  const number1 = 1234567890; 
const number1String = number1.toString();
console.log(number1String); //'1234567890'->很好
console.log(number1String.length); // 10->有效

const number2 = 123456789000000;
const number2String = number2.toString();
console.log(number2String); //'123456789000000'->很好
console.log(number2String.length); // 15->有效

const number3 = 1234567890000000000;
const number3String = number3.toString();
console.log(number3String); //'1234567890000000000'->很好
console.log(number3String.length); // 19->有效

const number4 = 12345678900000000000000000000000000000000000000;
const number4String = number4.toString();
console.log(number4String); //'1.23456789e + 40'->哦! 啊! h! 当然!
console.log(number4String.length); // 14->错误

请注意,最后一个数字以科学计数法表示,以减少所用数字的位数。 number4String 变量的确有14个字符,所有零都填入指数e+40

为了找到解决该问题的方法,我们需要考虑一下。 我们不能使用.length 方法,但是我们还有一个可用于执行计算的数字。

蛮力计算

假设我们的数字在十进制数字系统中,我们可以使用简单的数学运算来计算数字位数。

例如,让我们有一个数字100。很明显,这个数字中有3位数字,但是我们如何通过执行一些计算来实际获得该信息呢?

因此,我们需要通过做一些数学运算从100号获得3号。 我们可以尝试将其除以33.33,我们将接近3。唯一的问题是,这种方法不适用于数字200,并且需要它适用于每3位数字(从100到999。

显然,加法,减法和乘法不适用于所有这些数字,因此我们可以得出结论,除法仍然是可行的方法。 我们只需要找到最适合的数字即可。

我们真正需要的是,当我们将数字除一次时,结果实际上比起始数字少一位。 您说:“好吧,但是我们可以将100除以任意数字,而少得到一位,这有什么帮助?” 这是一个很好的观察,它使我们转到下一个条件,我们实际上需要能够将999除以相同的数字,并得到结果数字,该数字比999少一位。所以现在,我们看不到任何数字在1–9的范围内将无法解决问题。

让我们尝试将100除以10。

甲级:

第二师:

现在,让我们尝试将999除以10。

甲级:

第二师:

嗯,所以……不走运!? 不,不是。 在第二个示例中,总位数没有减少,但小数点前的位数实际上却在减少,并且与第一个示例中的位数减少的方式相同。 现在,让我们跟踪小数点前面的数字:

甲级:

第二师:

我们看到除法数为2,而除法数达到一位。 但是我们知道原始号码中有3位数字。 因此,如果我们再除一次,在这两种情况下我们分别得到0.1和0.999。

到现在为止,很明显我们的最终目标是……通过反复除以10来使值小于1。

在此示例中,我们进行了3个除法,它们与两个数字中的数字均匹配。 例如,如果我们尝试使用384698,您将获得以下信息:

  • 除法1 => 38469.8> 1 =>一位数字
  • 除2 => 3846.98> 1 =>两位数
  • 除3 => 384.698> 1 =>三位数
  • 除法4 => 38.4698> 1 =>四位数
  • 5除法=> 3.84698> 1 =>五位数
  • 6除法=> 0.384698 六位数

我们得到这个数字有6位数字,这是正确的。

所有这些只是一些简单的数学运算,现在我们需要将其转换为一个程序来执行此计算。 首先,让我们明确定义我们需要做什么:

当数字大于或等于1时,将其除以10,并在每个除法器上将数字的位数增加一。

该语句从字面上告诉我们如何编程。 通过使用while 环:

  让数字= 468168; 
令长度= 0;
而(数字> = 1){
数字=数字/ 10;
长度++;
}
console.log(length); // 6

这将始终在数学中起作用,尽管在JavaScript中并非总是如此,因为它的浮点怪异性,但它在大多数情况下都将起作用,并且最好由计算来完成。

使用指数

还有一种获取位数的方法,该方法不需要我们进行任何计算,并且可以使用JavaScript的内置方法来获取所需的数字。 让我们看看如何做到这一点。

好的,所以问题在于数字是以科学计数法书写的,从而限制了其字符串表示形式中的字符数,并且我们无法使用.length字符串方法来获取数字位数。 但是,我们可以使用该科学计数法中的信息来实际获得位数。 为此,让我们用科学计数法写一个数字:

  const number = 3.1131e + 7 //这是31131 000 

我们看到该数字的位数应为8。 让我们再做一个:

  const number = 7.35e + 17 //这是735000000000000000000 

这个有18位数字。 现在我们可以看到一个模式,显示指数值的数字实际上告诉我们小数点后有几位数。 在第二个示例中,我们从数字中看到两位数,其余全部为零,加在一起为17位。 要获取完整位数,我们需要做的就是在指数值上加一个,我们得到18位的正确值:

  常量= 4.68e + 25; 
const string = number.toString();
const exponent = string.split('e')[1] .substring(1);
const numberOfDigits = parseInt(exponent)+ 1;
console.log(numberOfDigits); // 26

我们在这里做了什么? 在第二行中,我们将数字转换为字符串,以便能够使用字符串方法。 第三行,我们做几件事。 首先我们分割string 在字符e string.split('e') ),它为我们提供了两个字符串['4.68', '+25']的数组。 该数组的第二个成员是指数值,因此我们使用string.split('e')[1] 。 现在我们有了一个带有指数值的字符串,我们只对数字感兴趣,而对符号不感兴趣。 因此,我们可以使用. substring . substring 在加号后获取所有内容的方法: string.split('e')[1].substring(1) 。 现在我们有了字符串'25' ,我们需要在下一行中添加一个,但是我们需要注意不要将数字1连接到该字符串。 这就是为什么我们使用parseInt() 将字符串'25'制成数字并安全进行加法的方法。

现在,这里要记住一件事。 数字4.68e+25 也可以写成46.8e+24 468e+23 4680e+22等。位数仍然是指数值加上小数点前的位数,因此始终为26。只要该值是number类型 没关系 当我们以字符串类型(而不是数字类型)获取此数字时,就会出现问题,而且大多数情况下,我们从输入字段中以通常会获取字符串的形式获取值。 如果将解决方案应用于这样编写的字符串,则会得到错误的结果。 幸运的是,这很容易解决,我们所要做的就是将我们得到的字符串转换为数字,然后再次返回字符串,然后可以将解决方案应用于该字符串:

  const value ='468e + 23'; 
const number = Number(value); //这会将数字重新格式化为“ 4.68e + 25”,即所谓的“规范化”科学计数法
const string = number.toString();
const exponent = string.split('e')[1] .substring(1);
const numberOfDigits = parseInt(exponent)+ 1;
console.log(numberOfDigits); // 26

当然,如果我们得到正常表示的数字,即不是用科学计数法表示的数字,则此方法将再次失败,因为它没有指数。 因此,我们需要添加一个条件来检查我们电话号码的格式。 让我们将其包装到一个函数中并添加以下检查:

  函数getDigits(value){ 
const number = Number(value);
const string = number.toString();
const hasExponent = string.indexOf('e')!== -1; //是用科学记数法写的数字

如果(具有指数){
const exponent = string.split('e')[1] .substring(1);
返回parseInt(exponent)+ 1;
}

返回number.toString()。length;
}

//作为字符串
console.log(getDigits('468e + 23')); // 26
console.log(getDigits('12345678')); // 8
//作为数字
console.log(getDigits(468e + 23)); // 26
console.log(getDigits(12345678)); // 8

在这里,如果数字中有指数部分,我们将其number.toString().length为指数并返回指数值加1。如果没有指数,则返回number.toString().length 这直接给了我们位数。

我制作了一个简单的应用程序,您可以在输入字段中输入数字并查看本文所述方法的效果。 只需点击以下链接:

应用范例

本文中描述的问题是我们在实践中很少遇到的问题,但我认为值得牢记这一点。 解决方案并不难,特别是对于有经验的开发人员而言,但对于没有经验的开发人员来说,这可能是个问题,他们可能甚至没有意识到,因为number.toString().length 对于大约22位数字的长数字,它工作得很好,在那之后我开始觉得事情更“科学”了。 🤓

我希望您学到了一些新知识,或者至少从中获得了一些乐趣。 感谢您的阅读!