从长变量中获取第二个数字

Getting the second digit from a long variable

我正在尝试从一个 long 变量中获取第二个数字。

long mi = 110000000;
int firstDigit = 0;
String numStr = Long.toString(mi);
for (int i = 0; i < numStr.length(); i++) {
    System.out.println("" + i + " " + numStr.charAt(i));
    firstDigit =  numStr.charAt(1);
}

当我在控制台上打印 firstDigit = numStr.charAt(1) 时。我得到 1,这是预期的,但是当循环结束时 firstDigit49。 有点不明白为什么。

您可能正在寻找 Character.getNumericValue(...)

firstDigit = Character.getNumericValue(numStr.charAt(1));

否则,由于变量 firstDigitint 类型,这意味着您分配的 ASCII representation of the character '1' 是 49 而不是指定索引处的整数。

此外,请注意,由于您只对特定数字感兴趣,因此无需将语句 firstDigit = numStr.charAt(1); 放入循环中。

相反,只需在循环外执行以下操作。

int number = Character.getNumericValue(numStr.charAt(1));

因为 49 是 char '1' 的 ASCII 值。

所以你不应该直接把一个char赋值给int。

并且您在这里不需要一个循环,它无论如何都会用 charAt(1) 验证当前值。

int number = numStr.charAt(1) - '0'; // substracting ASCII start value 

上面的语句在内部像 49 -48 一样工作并给你 1。

如果你觉得那样很混乱,就像其他人所说的那样使用Character.getNumericValue();

或者,虽然我不喜欢 ""+ hack,但下面应该可行

int secondDigit = Integer.parseInt("" + String.valueOf(mi).charAt(1));

你只需要将firstDigit定义为一个char类型的变量,这样就会打印成字符。 因为你定义为 int 变量,它的值是 char '1' 的 ASCII 值:49。这就是你得到 49 而不是 1 的原因。

你感到困惑,因为 49 是整数 1 的 ASCII 值。所以你可以将字符解析为整数,然后你可以看到整数值。

    Integer.parseInt(String.valueOf(mi).charAt(1)):

试试这个来获取 long 的第二个字符

mi.toString().charAt(1);

一起来看看

System.out.println(numStr.charAt(1));
firstDigit =  numStr.charAt(1);
System.out.println(firstDigit);

结果与你得到的不一样

1
49

发生这种情况是因为您的 firstDigitint。将其更改为 char,您将得到预期的结果

How to get ASCII code

int ascii = 'A';
int ascii = 'a';

因此,如果您将一个字符分配给一个整数,该整数将保存该字符的 ASCII 值。在这里我明确地给出了值,在你的代码中你调用了一个 returns 一个字符的方法,这就是你得到 ASCII 而不是数字的原因。

您也可以按照下面的方式进行,

firstDigit = Integer.parseInt( numStr.charAt(1)+"");

因此它将打印长数字的第二个数字。

答案Integer.parseInt(String.valueOf(mi).charAt(1)+"");是正确的。

但是,如果我们想在我们的程序中考虑性能,我们需要一些改进。

我们要耗时的方法,Integer.parseInt()String.valueOf()。而且自定义方法总是比 Integer.parseInt()String.valueOf() 快得多。参见 simple benchmarks

所以,高性能解决方案可以像下面这样:

int y=0;
while (mi>10)
{
    y=(int) (mi%10);
    mi=mi/10;
}
System.out.println("Answer is: " + y);

进行测试:

long mi=4642345432634278834L;
int y=0;

long start = System.nanoTime();

//first solution
//y=Integer.parseInt(String.valueOf(mi).charAt(1)+"");      

//seconf solution
while (mi>10)
{
    y=(int) (mi%10);
    mi=mi/10;
}

long finish = System.nanoTime();

long d = finish - start;
System.out.println("Answer is: " + y + " , Used time: " + d);

//about 821 to 1232 for while in 10 runs
//about 61225 to 76687 for parseInt in 10 runs

通过字符串操作来处理数字几乎总是错误的方法。

要获得第二个数字,请使用以下命令;

int digitnum = 2;

int length = (int)Math.log10(mi));
int digit = (int)((mi/Math.pow(base,length-digitnum+1))%base);

如果你想要一个不同于第二个数字的数字。

为了避免浮点数的不确定性,您可以使用像 guavas 这样的整数数学库 IntMath

还没有提到的一些东西:

  • 整数数据类型的第二个数字是 undefined 如果长数是 0-9(不,它不是零。整数没有小数位, 这只对浮点数是正确的。即便如此你必须 return undefined 对于 NaN 或无穷大值)。在这种情况下,您应该 return 一个哨兵,例如-1表示没有第二个数字。

  • 使用 log10 获取特定数字看起来很优雅,但它们是 1. 数字上最昂贵的函数之一,并且 2. 在边缘情况下经常给出不正确的结果。后面会给出一些反例。

性能可以进一步提高:

public static int getSecondDigit(long value) {
long tmp = value >= 0 ? value : -value;
if (tmp < 10) {
  return -1;
}

long    bigNumber = 1000000000000000000L;
boolean isBig     = value >= bigNumber;

long  decrement   = isBig ? 100000000000000000L : 1;
long  firstDigit  = isBig ? bigNumber : 10;
int   result      = 0;
if (!isBig) {
  long test = 100;

  while (true) {
    if (test > value) {
      break;
    }
    decrement = firstDigit;
    firstDigit = test;
    test *= 10;
  }
}



// Remove first
while (tmp >= firstDigit) {
  tmp -= firstDigit;
}

// Count second
while (tmp >= decrement) {
  tmp -= decrement;
  result++;
}

return result;
}

比较: 1 000 000 个随机多头

String.valueOf()/Character.getNumericValue():106 毫秒
Log/Pow 泰米尔:151 毫秒
@Gholamali-Irani 的 Div10:45 毫秒
以上例程:30 毫秒

这还没有结束,通过查找表可以更快 递减 1/2/4/8, 10/20/40/80 并避免使用乘法。