On Integer Input Optimization

Keywords: Linux ascii

background

A few days ago, I found the difference between write-in optimization and non-write-in optimization.

Other people's code:

My code:

I seem to have found something...

Then I click on the number one code to see:

void get(int &res){ 
    char ch;bool flag=0; 
    while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true); 
    for(res=num;isdigit(ch=getchar());res=res*10+num); 
    (flag)&&(res=-res); 
}

At that time, I was foolish. A small function can be so fast!
When I analyze functions, I don't understand the meaning of (ch='-') & (flag = true) and (flag) & (res= - res). Then I analyze:

(A) & (B) is to determine whether A is valid or not. If A is valid, B is the statement executed (e.g. a=b), then B is executed.

This is read optimization!
Then I gathered some information, this writing is more pretentious, will be hit by thunder, so we are still down-to-earth, starting from scratch.

Principle and Implementation of Read-in Optimization

There are many kinds of input modes in C++, and scanf and cin are the most common ones, because these two functions are more useful. In addition, there are some functions to read characters, to popularize:

#include<cstdio>
#include<cstring>
int main()
{
    char c[];
    int len=strlen(c);//To get the length of the c array, you need to use the # include < CString > header file

    gets(c);//Read in a line of string, stop after encountering return, you can read infinitely, will not judge the upper limit, so it is easy to overflow. And this function, which was removed in ISO/IEC 9899 2011(C11) standard.

    fgets(c,len,stdin);//Similar to the gets function, reading len is longer than len or stops whenever you encounter a carriage return, so read len-1 at most each time (because the last' 0'placeholder in the character array)

    c[0]=getchar();//Like scanf, you can directly assign a character by reading it in and returning it. You need to use the # include < cstdio > header file. Unlike scanf, this function is a non-buffered input function, which means it is faster than scanf.

    c[0]=getch();//Read a character directly without echo (but in linux). That is to say, you read a character, it will not be displayed in the interface, but directly read the character, getch will also directly return the character. For example, if you write a program game, you certainly don't want to see wasd flying all over the sky, so use getch. Require # include < conio. H > header file. Again, it has no buffer.
}

getchar is faster than scanf.

Can we use getchar to improve our input?

Certainly. First, getchar is read in character by character, so we need to read in character by character, but if we want to carry it, we need to multiply it by 10, because it is ASCII code, we need to subtract it by 0. For example, the character `1', `1'- `0' is the number 1.

After that, let's simulate the process.
Assume input 2018.

  1. The program reads in the character `2', `2'- `0' to get the number 2, ans=0*10+2=2.
  2. The program reads in the character `0', `0'- `0' to get the number 0, ans=2*10+0=20.
  3. The program reads in the characters `1', `1'- `0' to get the number 1, ans=20*10+1=201.
  4. The program reads in the character'8','8'-'0' to get the number 8, ans=201*10+8=2018.

Basically, that's the case. I won't give you examples one by one.
According to the above logic, ans=ans*10+ch-'0'.

But sometimes you enter this:
123 456 789

What if there is a space between every two numbers?

Well, read the space before the number first, that is, read it in until the number appears.
So we can give the first generation of programs:

void get(int &a)
{
    a=0;
    char ch;
    while(ch<'0'||ch>'9') c=getchar();
    while(ch>='0'&&ch<='9') a=a*10+c-'0',c=getchar();
}

How to deal with negative numbers?

I believe some readers will say that directly multiply the number by - 1, but initially the number is 0, multiplied by any number is 0, it is certainly not possible to do so.
So long as the marker is set to 1 at the beginning, before reading the integer, if there is a sign ('-'), then the marker is set to - 1, and finally the number is multiplied by the marker.

Somebody must have said, what's the ghost of the isdigit function at the beginning?
In fact, this function is to detect characters that are not Arabic numerals 0 to 9, so we can also use this function to reduce the amount of code.
Note: Use the # include < iostream > header file.

Code

Ultimately, there are two kinds of code.

void get(int &p){
    int flag=1;char ch;
    for(p=0;!isdigit(ch);ch=getchar()) if(ch=='-') flag=-1;
    for(;isdigit(ch);ch=getchar()) p=p*10+ch-'0';
    p*=flag;
}

This code can get(int) directly.

int get(){
    int flag=1,p=0;char ch;
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') flag=-1;
    for(;isdigit(ch);ch=getchar()) p=p*10+ch-'0';
    return p*flag;
}

This code int=get() will do.

Verify the efficiency of read-in optimization

Data Manufacturing Procedure

freopen is used to generate 1000000 texts, and scanf, cin and read-in are used to optimize the reading.

#include<cstdio>
const int N=1000000;
int main()  
{  
    freopen("test.txt","w",stdout);//Save the output as a file
    for(int i=1;i<=4;i++)//Test four kinds of read-in programs: direct get, assignment get,scanf,cin
    {
        for(int j=1;j<=N;j++)  
            printf("%d ",i);
        puts("");
    }
} 

Test program

#include<ctime>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=1000000;
void get_tradition(int &p){
    int flag=1;char ch;
    for(p=0;!isdigit(ch);ch=getchar()) if(ch=='-') flag=-1;
    for(;isdigit(ch);ch=getchar()) p=p*10+ch-'0';
    p*=flag;
}
int get_assignment(){
    int flag=1,p=0;char ch;
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') flag=-1;
    for(;isdigit(ch);ch=getchar()) p=p*10+ch-'0';
    return p*flag;
}
int main()
{
    freopen("test.txt","r",stdin);//Read in the test file
    int x;
    double t1=clock();
    for(int i=1;i<=N;i++)
        get_tradition(x);
    double t2=clock();
    double t3=clock();
    for(int i=1;i<=N;i++)
        x=get_assignment();
    double t4=clock();
    double t5=clock();
    for(int i=1;i<=N;i++)
        scanf("%d",&x);
    double t6=clock();
    double t7=clock();
    for(int i=1;i<=N;i++)
        cin>>x;
    int t8=clock();
    printf("When number is %d,\n",N);
    printf("get_tradition   took %.3lf second(s)\n",(t2-t1)/1000);
    printf("get_assignment  took %.3lf second(s)\n",(t4-t3)/1000);
    printf("scanf           took %.3lf second(s)\n",(t6-t5)/1000);
    printf("cout            took %.3lf second(s)\n",(t8-t7)/1000);
}

summary

When number is 1000000,
get_tradition took 0.062 second(s)
get_assignment took 0.063 second(s)
scanf took 0.312 second(s)
cout took 2.094 second(s)

Read-in optimizations are not loaded, but really save time, saving 0.25 seconds on an average of 1000,000 inputs. So read-in optimization is for topics with more data, so let's form the habit of write-in optimization!

Posted by john_6767 on Thu, 11 Jul 2019 15:02:34 -0700