working of a faster I/O method - c++

I was studying faster I/O methods for programming problems,
I found out this method of using getchar_unlocked() (though risky but still).
I looked around quite a bit but couldn't get how it scanned an integer value
or in other words what do the 4 lines mean and how they work in the scanint() function
defined below
#include<iostream>
#include<cstdio>
#define gc getchar_unlocked
void scanint(int &x)
{
register int c = gc();
x = 0;
for(;(c<48 || c>57);c = gc());
for(;c>47 && c<58;c = gc())
{x = (x<<1) + (x<<3) + c - 48;}
}
int main()
{
int n,k;
scanint(n);
scanint(k);
int cnt=0;
while(n--)
{
int num;
scanint(num);
if(num%k==0)cnt++;
}
printf("%d",cnt);
return 0;
}

The code has hard-coded ASCII values for the chars '0' and '9', so it skips over anything which does not lie in that range (the first for loop in the four lines of interest to you).
Then while it sees characters in the '0' - '9' range it multiplies its running total by 10 (by shifting it left once to double it, then adding that to itself shifted left three times, which is like multiplying by 8) and adds the current char - the code for '0'.

ASCII value of '0' is 48, and each subsequent digit goes one more. i.e. '1'->49, '2'->50... and so on.
A side effect of this is that if you take a character digit, meaning something between '0' and '9', and subtract the ASCII value of '0' from it, then you get the integer value of that digit.
So in the line x = (x<<1) + (x<<3) + c - 48;, the c-48 part is converting the digit character (an ASCII coded character) into a number between 0-9 that refers to that character.
(x<<1)+(x<<3) is the same as x * 10,(For more information, checkout http://en.wikipedia.org/wiki/Multiplication_algorithm#Shift_and_add and How can I multiply and divide using only bit shifting and adding? ) in fact this part of the code is unnecessarily obfuscated. The compiler can optimize multiplication in many different ways to make it as fast as possible, so we don't need to manually implement the bit shifting. It makes for an interesting college level puzzle though.
for(;(c<48 || c>57);c = gc()); This loop will ignore all the characters until it receives one that falls within the '0' to '9' range. So if the user started by typing a space or any other character, it'll simply be ignored.
By the time the code hits for(;c>47 && c<58;c = gc()) {x = (x<<1) + (x<<3) + c - 48;} line, the variable c is already initialized to the first digit that the user has typed. This loop leaves the initialization empty so the control flow will dive right into the loop and start computing the number as each character is typed.
The loop will go on as long as the user keeps typing digits, as soon as the user types something other than a digit, the loop will terminate, finalizing the number.
Until the user keeps typing digits, the line x = (x<<1) + (x<<3) + c - 48; will keep getting executed over and over again, with each time c being the character just typed. And x will multiply itself by 10 and add the new digit in.
Let's say the user types 2014. Here's how the values in c and x will progress.
c = '2' #ASCII value 50
x = 2
c = '0' #ASCII value 48
x = 20
c = '1' #ASCII value 49
x = 201
c = '4' #ASCII value 52
x = 2014
HTH.

The line
for(;(c<48 || c>57);c = gc());
reads the characters which are not in between '0' to '9'.
The line
for(;c>47 && c<58;c = gc())
reads the characters between '0' to '9' one by one.
The line
{x = (x<<1) + (x<<3) + c - 48;}
is simply equivalent to
x = 10 * x + c - 48;
A simplified version of this function can be rewritten as:
#define gc getchar_unlocked
int read_int()
{
char c = gc();
while(c<'0' || c>'9')
c = gc();
int ret = 0;
while(c>='0' && c<='9')
{
ret = 10 * ret + c - 48;
c = gc();
}
return ret;
}

Related

What is '0' means? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 1 year ago.
Improve this question
I'm new to programming and sometimes see expressions like this
...
for (int i=0; i<str1.length(); i++)
{
int sum = ((str1[i]-'0')+(str2[i]-'0'));
str.push_back(sum%10 + '0');
}
...
So that is '0' here? Is it some kind of converting or something?
It's literally the character zero '0'
The operation str[i] - '0' is used to convert the representation of a digit into its numeric value.
Since the characters from '0' to '9' are following in the ascii table, having respectively, the values 48 to 57, when you perform the operation '3' - '0', the interpreter will use the ascii values, 51 - 48 == 3, so you can convert '3' to 3
ASCII Table
(source of the picture : Wikipedia)
'0' is the character zero. Since characters are sequential, adding a digit to 0 will produce the character representing that digit (once cast back to a char). E.g., (char)(2 + '0') (i.e., the integer two plus the character zero) will produce '2' (i.e., the character two).
Well
str2[i] - '0'
Converts character representation of a digit ('3', '7', '9') into its integer value (3, 7, 9). More accurate (and more wordy) construction is
(int)char.GetNumericValue(str2[i])
What is implied, but not really stated, in the other answers is that int and char can be treated as fairly equivalent in c#. You can do math on chars just like you can on ints, and you can convert back and forth between int and char with ease. The number you get is based on the position in the utf8 character tables for the char.
'0' as a char has an int value of 48, so you could do:
int x = 7;
char c = x+48; //c would be '7' as a char, or 55 as an int
Other examples:
char c = 'a';
c++;
Console.Write(c); //prints 'b', because 'a' + 1 is b
It's quite logical and reasonably helpful sometimes* but the main reason you might see '0' is that it's easier to remember '0' than it is to remember 48 (it's slightly easier to remember the hex version 0x30)
All these give you char 5 from int 5:
char five = 5 + 48;
char five = 5 + 0x30;
char five = 5 + '0';
Which one would you find easiest to remember? :)
*for example, say you wanted to count the chars in an ascii string, you could do:
var counts = new int[256];
foreach(char c in string)
counts[c]++;
You can use the char to index the array just like you can an int. At the end of the operation "hello world" would have put a 1 in index 104 (the h), a 3 in index 108(the l) etc..
Sure these days you might use a Dictionary<char, int> but appreciating that intrinsic char/int equivalence and how it can be used has its merits..
What is '0' means?
In C++, it is a character literal.
The fundamental reason why/how str1[i] - '0' works is through promotion.
In particular when you wrote:
str1[i]-'0'
This means
both str1[i] and '0' will be promoted to an int. And so the result will be an int.
Let's looks at some example for more clarifications:
char c1 = 'E';
char c2 = 'F';
int result = c1 + c2;
Here both c1 and c2 will be promoted to an int. And the result will be an int. In particular, c1 will become(promoted to) 69 and c2 will become(promoted to) 70. And so result will be 69 + 70 which is the integer value 139.

Substraction string on string and multiply by int role

I am having issue to understand this code. The goal is to add the sum of all digit from a number until there is only 1 digit recursively
long long superDigit(string n, int k) {
if (n.size() == 1)
return stoi(n);
long long sum = 0;
for (int i = 0 ; i < n.size() ; i++)
sum += (n[i] - '0') * k;
return superDigit(to_string(sum),1);
}
However, i don't understand this line
sum += (n[i] - '0') * k;
n is a string k is an integer what to expect from this kind of multiplication ?
Moreover i tested the operator - on string and i don't get how it works.
Every character has a numerical value. You can find these values on the ASCII Table. The characters 0-9 are placed in a contiguous chunk on the ASCII table, with 0 at 48 and 9 and 57. So, when you do a char minus '0', you get how far away it is from '0' on the ASCII table, effectively converting the character to its corresponding number. '0' - '0' is 0 since they're the same character, '1' - '0' is 1 since 1 is right next to 0 (49 - 48), '2' - '0' is 2 since it's 2 away (50 - 48 = 2), and so on.

C++- Adding or subtracting '0' from a value

I was looking at the code below and I got the logic but I cannot seem to understand what is the use of '0'.
class Solution
{
public:
string addBinary(string a, string b)
{
string s = "";
int c = 0, i = a.size() - 1, j = b.size() - 1;
while(i >= 0 || j >= 0 || c == 1)
{
c += i >= 0 ? a[i --] - '0' : 0;
c += j >= 0 ? b[j --] - '0': 0;
s = char(c % 2 + '0') + s;
c /= 2;
}
return s;
}
};
The C and C++ standards require that the characters '0'..'9' be contiguous and increasing. So to convert one of those characters to the digit that it represents you subtract '0' and to convert a digit to the character that represents it you add '0'.
C++ requires ([lex.charset]/3) that, in the basic character set, the numerals '0', '1', '2', ..., '9' are encoded as contiguous values. That means that given a numeral character c, you can compute its integral value as the expression c - '0'.
The value '0' represent offset of ascii table for numeric character representation.
To compare two values when one is ascii and another is binary you need to convert to same base representation.
In ASCII code character 0, represented as '0' in C (and many other languages) has the value 48. Also in ASCII the other 9 numerals are contiguous: '0', '1', etc.
A string is composed of characters. So if you subtract '0' to another numeral you get its numeric value.

VBA convert Excel Style Column Name (with 52 charset) to original number

I have a c++ program that takes an integer and convert it to lower and uppercase alphabets, similar to what excel does to convert column index to column number but also including lower case letters.
#include <string>
#include <iostream>
#include <climits>
using namespace std;
string ConvertNum(unsigned long v)
{
char const digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
size_t const base = sizeof(digits) - 1;
char result[sizeof(unsigned long)*CHAR_BIT + 1];
char* current = result + sizeof(result);
*--current = '\0';
while (v != 0) {
v--;
*--current = digits[v % base];
v /= base;
}
return current;
}
// for testing
int main()
{
cout<< ConvertNum(705);
return 0;
}
I need the vba function to reverse this back to the original number. I do not have a lot of experience with C++ so I can not figure out a logic to reverse this in vba. Can anyone please help.
Update 1: I don't need already written code, just some help in the logic to reverse it. I'll try to convert the logic into code myself.
Update 2: Base on the wonderful explanation and help provided in the answer, it's clear that the code is not converting the number to a usual base52, it is misleading. So I have changed the function name to eliminate the confusion for future readers.
EDIT: The character string format being translated to decimal by the code described below is NOT a standard base-52 schema. The schema does not include 0 or any other digits. Therefore this code should not be used, as is, to translate a standard base-52 value to decimal.
O.K. this is based on converting a single character based on its position in a long string. the string is:
chSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
The InStr() function tells us the A is in position 1 and the Z is in position 26 and that a is in position 27. All characters get converted the same way.
I use this rather than Asc() because Asc() has a gap between the upper and lower case letters.
The least significant character's value gets multiplied by 52^0The next character's value gets multiplied by 52^1The third character's value gets multiplied by 52^3, etc. The code:
Public Function deccimal(s As String) As Long
Dim chSET As String, arr(1 To 52) As String
Dim L As Long, i As Long, K As Long, CH As String
chSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
deccimal = 0
L = Len(s)
K = 0
For i = L To 1 Step -1
CH = Mid(s, i, 1)
deccimal = deccimal + InStr(1, chSET, CH) * (52 ^ K)
K = K + 1
Next i
End Function
Some examples:
NOTE:
This is NOT the way bases are usually encoded. Usually bases start with a 0 and allow 0 in any of the encoded value's positions. In all my previous UDF()'s similar to this one, the first character in chSET is a 0 and I have to use (InStr(1, chSET, CH) - 1) * (52 ^ K)
Gary's Student provided a good and easy to understand way to get the number from what I call "Excel style base 52" and this is what you wanted.
However this is a little different from the usual base 52. I'll try to explain the difference to regular base 52 and its conversion. There might be an easier way but this is the best I could come up with that also explains the code you provided.
As an example: The number zz..zz means 51*(1 + 52 + 52^2 + ... 52^(n-1)) in regular base 52 and 52*(1 + 52 + 52^2 + ... 52^(n-1)) in Excel style base 52. So Excel style get's higher number with fewer digits. Here is how much that difference is based on number of digits. How is this possible? It uses leading zeros so 1, 01, 001 etc are all different numbers. Why don't we do this normally? It would mess up the easy arithmetic of the usual system.
We can't just shift all the digits by one after the base change and we can't just substract 1 before the base change to counter the fact that we start at 1 instead of 0. I'll outline the problem with base 10. If we'd use Excel style base 10 to number the columns, we would have to count like "0, 1, 2, ..., 9, 00, 01, 02, ...". On the first glance it looks like we just have to shift the digits so we start counting at 1 but this only works up to the 10th number.
1 2 .. 10 11 .. 20 21 .. 99 100 .. 110 111 //normal counting
0 1 .. 9 00 .. 09 10 .. 88 89 .. 99 000 //excel style counting
You notice that whenever we add a new digit we shift again. To counter that, we have to do a shift by 1 before calculating each digit, not shift the digit after calculating it. (This only makes a difference if we're at 52^k) Note that we still assign A to 0, B to 1 etc.
Normally what you would do to change bases is looping with something like
nextDigit = x mod base //determining the last digit
x = x/base //removing the last digit
//terminate if x = 0
However now it is
x = x - 1
nextDigit = x mod base
x = x/base
//terminate if x = 0
So x is decremented by 1 first! Let's do a quick check for x=52:
Regular base 52:
nextDigit = x mod 52 //52 mod 52 = 0 so the next digit is A
x = x/52 //x is now 1
//next iteration
nextDigit = x mod 52 //1 mod 52 = 1 so the next digit is B
x = x/52 //1/52 = 0 in integer arithmetic
//terminate because x = 0
//result is BA
Excel style:
x = x-1 //x is now 51
nextDigit = x mod 52 //51 mod 52 = 51 so the next digit is z
x = x/52 //51/52 = 0 in integer arithmetic
//terminate because x=0
//result is z
It works!
Part 2: Your C++ code
Now for let's read your code:
x % y means x mod y
When you do calculations with integers, the result will be an integer which is achieved by rounding down. So 39/10 will produce 3 etc.
x++ and ++x both increment x by 1.
You can use this in other statements to save a line of code. x++ means x is incremented after the statement is evaluated and ++x means it is incremented before the statement is evaluated
y=f(x++);
is the same as
y = f(x);
x = x + 1;
while
y=f(++x);
is the same as
x = x + 1;
y = f(x);
This goes the same way for --
Char* p creates a pointer to a char.
A pointer points to a certain location in memory. If you change the pointer, it points to a different location. E.g. doing p-- moves the pointer one to the left. To read or write the value that is saved at the location, use *p. E.g. *p="a"; "a" is written to the memory location that p points at. *p--="a"; "a" is written to the memory but the pointer is moved to the left afterwards so *p is now whatever is in the memory left of "a".
strings are just arrays of type char.
The end of a string is always '\0' if the computer reads a string it continues until it finds '\0'
This is hopefully enough to understand the code. Here it is
#include <string>
#include <iostream>
#include <climits>
using namespace std;
string base52(unsigned long v)
{
char const digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; //The digits. (Arrays start at 0)
size_t const base = sizeof(digits) - 1; //The base, based on the digits that were given
char result[sizeof(unsigned long)*CHAR_BIT + 1]; //The array that holds the answer
//sizeof(unsigned long)*CHAR_BIT is the number of bits of an unsigned long
//which means it is the absolute longest that v can be in any base.
//The +1 is to hold the terminating character '\0'
char* current = result + sizeof(result); //This is a pointer that is supposed to point to the next digit. It points to the first byte after the result array (because its start + length)
//(i.e. it will go through the memory from high to low)
*--current = '\0'; //The pointer gets moved one to the left (to the last char of result and the terminating char is added
//the pointer has to be moved to the left first because it was actually pointing to the first byte after the result.
while (v != 0) { //loop until v is zero (until there are no more digits left.
v--; //v = v - 1. This is the important part that does the 1 -> A part
*--current = digits[v % base]; // the pointer is moved one to the left and the corresponding digit is saved
v /= base; //the last digit is dropped
}
return current; //current is returned, which points at the last saved digit. The rest of the result array (before current) is not used.
}
// for testing
int main()
{
cout<< base52(705);
return 0;
}

Change bit of hex number with leading zeros in C++,(C)

I have this number in hex string:
002A05.
I need to set 7-th bit of this number to 1, so after conversion I will get
022A05
But it has to work with every 6 chars hex number.
I tried converting hex string to integer via strtol, but that function strip leading zeros.
Please help me how can I solve it.
int hex=0x002A05;
int mask = 0x020000;
printf ("%06X",hex | mask);
hope this helps
In a 24-bit number bit #7 (counting from the left, as you did in your example, not from the right, as is done conventionally) is always going to be in the second byte from the left. You can solve your problem without converting the entire number to integer by taking that second hex digit, converting it to a number 0..15, setting its bit #3 (again counting from the left), and converting the result back to a hex digit.
int fromHex(char c) {
c = toupper(c);
if (c >= '0' && c <= '9') {
return c-'0';
} else {
return c-'A'+10;
}
}
char toHexDigit(int n) {
return n < 10 ? '0'+n : 'A'+n-10;
}
char myNum[] = "002A05";
myNum[1] = toHexDigit(fromHex(myNum[1]) | 2);
printf("%s\n", myNum);
This prints '022A05' (link to ideone).
It sounds to me like you have a string, not a hex constant, that you want to manipulate. You can do it pretty easily by bit twiddling the ascii value of the hex character. If you have char representing a hex character like char h = '6';, char h = 'C';, or char h = '';, you can set the 3rd from the left (2nd from the right) bit in the number that the character represents using:
h = h > '7' ? h <= '9' ? h + 9 : ((h + 1) | 2) - 1 : h | 2;
So you can do this to the second character (4 + 3 bits) in your string. This works for any hex string with 2 or more characters. Here is your example:
char hex_string[] = "002A05";
// Get the second character from the string
char h = hex_string[1];
// Calculate the new character
h = h > '7' ? h <= '9' ? h + 9 : ((h + 1) | 2) - 1 : h | 2;
// Set the second character in the string to the result
hex_string[1] = h;
printf("%s", hex_string); // 022A05
You asked about strtol specifically, so to answer your question, just add padding after you convert the number with strtol:
const char *s = "002A05";
int x = strtol(s, NULL, 16);
x |= (1<<17);
printf("%.6X\n",x);