0

I recently learnt that using getchar_unlocked() is a faster way of reading input. I searched on the internet and found the code snippet below: But I am unable to understand it.

void fast_scanf(int &number)
{
    register int ch = getchar_unlocked();
    number= 0;

    while (ch > 47 && ch < 58) {
        number = number * 10 + ch - 48;
        ch     = getchar_unlocked();
    }
}

int main(void)
{
    int test_cases;fast_scanf(test_cases);

    while (test_cases--) 
   {
        int n;
        fast_scanf(n);
        int array[n];
        for (int i = 0; i < n; i++)
            fast_scanf(array[i]);
    }
return 0;
}

So, this code takes input for an integer array of size n for a given number of test_cases . I didn't understand anything in the function fast_scanf, like why this line:

while (ch > 47 && ch < 58) 
{ number = number * 10 + ch - 48;

why the register is used while declaring ch?

why the getchar_unlocked() is used twice in the function? and so on.. It would be great help if someone elaborates this for me. Thanks in advance!

alk
  • 69,737
  • 10
  • 105
  • 255
  • 2
    `register` is a storage class which provides the hint to the compiler to prefer storage in a CPU register for this variable. This is left from the earliest C compilers (with less optimization facilities). Nowadays, it's rather useless as the compiler is often much more clever to optimize at low level than the developer. It was never more than a hint which the compiler could ignore in case. [SO: Replacement for deprecated register keyword C++ 11](https://stackoverflow.com/a/30809775/7478597) – Scheff's Cat Oct 20 '18 at 10:22
  • 1
    `getchar_unlocked` is not standard C++. Also what are you trying to achieve with `register int`? – UnholySheep Oct 20 '18 at 10:22
  • @UnholySheep As I stated above, this code isn't mine. And I am new in programming, so I don't understand much of the code above –  Oct 20 '18 at 10:24
  • @Scheff Can you please explain about the `while` loop? –  Oct 20 '18 at 10:25
  • *"why the getchar_unlocked() is used twice in the function?"* - So that it exits the loop, see the loop will never break if you don't... I don't know why he wrote magic numbers like 47 and 57 instead of `while (ch >= '0' && ch <= '9')`... – Ruks Oct 20 '18 at 10:26
  • Have a look at the [ASCII table](https://en.wikipedia.org/wiki/ASCII). The characters for digits `0` ... `9` have the codes 48 ... 57. The while condition simply checks that the character in `ch` is a digit character. To convert it to an `int` number you have to subtract `48` to convert `'0'` to `0`, `'1'` to `1`, etc. – Scheff's Cat Oct 20 '18 at 10:29
  • @Ruks I think 47 to 58 must be the ascii values for the charaters 0 to 9 –  Oct 20 '18 at 10:30
  • Yes they are... ASCII characters go up from 0 to 255 having their respective characters while some are escape codes like 10 (`'\b'`, backspace) which is the ASCII value for backspace but actually **is not a character...**... – Ruks Oct 20 '18 at 10:31
  • `'0'` provides the identical value like `48`. Please, consider the `>` in `while (ch > 47`. It could be as well `while (ch >= '0'` as pointed out by @Ruks. However, the latter is easier to understand. – Scheff's Cat Oct 20 '18 at 10:33
  • why is `number*10` used? –  Oct 20 '18 at 10:34
  • @Ruks I executed this code on Ideone, [Code](https://ideone.com/2LstM3) . This prints the normal array. It doesn't multiply the values with 10. However, removing that `number*10` does not affect the output! –  Oct 20 '18 at 10:43
  • @Sandeshpatil I think that uses an old version of cplusplus because it should [never allow variable length of arrays](https://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard)... Use some other compiler like [wandbox](http://wandbox.org/)... – Ruks Oct 20 '18 at 11:02
  • Did you measure the time it takes for your program to run? Is it actually faster than fscanf()? – G. Sliepen Oct 20 '18 at 11:28
  • @Ruks -- ASCII codes run from 0 to 127. The values from 128 through 255 are used in various encodings known as "extended" ASCII and in the form of about a dozen standardized character sets defined by [ISO-8859](https://en.m.wikipedia.org/wiki/ISO/IEC_8859). – Pete Becker Oct 20 '18 at 14:03

1 Answers1

0

Okay, since what you are asking needs to be explained clearly, I am writing it here... so I don't jumble it all up inside the comments...

The function: (Edited it a bit to make it look like more C++-standard)

void fast_scanf(int &number)
{
    auto ch = getchar_unlocked();
    number= 0;
    while (ch >= '0' && ch <= '9')
    {
        number = number * 10 + ch - '0';
        ch     = getchar_unlocked();
    }
}

Here, take up consideration by looking at the ASCII Table first, since you won't understand how the results are coming up if you don't...

1) Here, you have a character ch takes up the input character from the user using getchar_unlocked() (The auto keyword does that automatically for you and is only usable in C++, not C)...

2) You assign the variable number to zero so that the variable can be re-used, note that the variable is a reference so it changes inside your program as well...

3) while (ch >= '0' && ch <= '9')... As pointed out, checks whether the characters is within the numerical ASCII limit, similar to saying that the character has to be greater than or equal to 48 but less than or equal to 57...

4) Here, things are a little bit tricky, Variable number is multiplied with the product of itself and 10 and the real integer value of the character you stored)...

5) In the next line, ch is reassigned so that you don't have to stay in the loop forever, since ch will remain that number forever if the user doesn't type anything... remember a loop goes back to where it was declared after reaching the end, checks if the condition is true, continues if it is true else breaks)...


For example: 456764

Here, ch will first take 4 then the others follow so we go with 4 first...

1) Number will be assigned to zero. While loop checks if the given character is a number or not, if it is continues the loop else breaks it...

2) Multiplication of 0 with 10 will be zero... and adding it with difference 52 (that is '4') with 48 (that is '0') gives you 4 (the real numerical value, not the char '4')... So the variable number now is 4...


And the same continues with the others as well... See...

number = number * 10 + '5' - '0'

number = 4 * 10 + 53 - 48

number = 40 + 5

number = 45... etc, etc. for other numbers...

Ruks
  • 3,886
  • 1
  • 10
  • 22