This question already has answers here:
What is the idea behind ^= 32, that converts lowercase letters to upper and vice versa?
(10 answers)
Closed 3 years ago.
I've found this code for swapping case, but I'm a bit confused on how it works.
class Main {
private static String swapCase(String s) {
String r = "";
for (char c : s.toCharArray())
r += c ^= 32; // this line
return r;
}
public static void main(String[] args) {
System.out.println(swapCase("Hello"));
}
}
I understood that it loops over each character. But, I can't wrap my head around the line (especially the XOR operator)
r += c ^= 32;
I mean what's the significance of 32? How it swaps the case?
This is how ASCII was set-up.
Letter from a-z have the 6-th bit set to 1; while letters from A-Z have the 6-th bit set to 0.
32 = 100000 // the 6-th bit is set to 1
doing a XOR with an int will invert that 6-th bit.
You could do a little of debugging and see yourself:
for (char c : s.toCharArray()) {
System.out.println(Integer.toBinaryString((int) c));
c ^= 32; // this line
System.out.println(Integer.toBinaryString((int) c));
}
For ASCII encoding 32 is the difference between a lower-case letter and an uppercase letter. It's a power of two, its binary representation is a single 1-bit:
0010 0000.
By applying the XOR assignment operator, you change this bit in the character value. Effectively adding (if the bit is 0 in c) or subtracting (bit is 1 in c) 32.
This will work fine for letters A-Z and a-z but will most likely do nonsense for most other characters in the input.
Let see this table and you will understand why
a = 01100001 A = 01000001
b = 01100010 B = 01000010
c = 01100011 C = 01000011
d = 01100100 D = 01000100
e = 01100101 E = 01000101
f = 01100110 F = 01000110
g = 01100111 G = 01000111
h = 01101000 H = 01001000
i = 01101001 I = 01001001
j = 01101010 J = 01001010
k = 01101011 K = 01001011
l = 01101100 L = 01001100
m = 01101101 M = 01001101
n = 01101110 N = 01001110
o = 01101111 O = 01001111
p = 01110000 P = 01010000
q = 01110001 Q = 01010001
r = 01110010 R = 01010010
s = 01110011 S = 01010011
t = 01110100 T = 01010100
u = 01110101 U = 01010101
v = 01110110 V = 01010110
w = 01110111 W = 01010111
x = 01111000 X = 01011000
y = 01111001 Y = 01011001
z = 01111010 Z = 01011010
The only difference from the upper and lower version is the 5th bit (count from 0). That's why with a simple XOR mask, you can change the case back and forth.
Related
For example:
If A -> 00001010(10), B-> 01000001(65), C -> 00011010(26)(Bit Map)
So after swapping specific bits, New A(A') -> 00000000 and
New B(B') -> 01001011
Explanation:
A -> 00001010
C -> 00011010(Swap bits b/w A and B if C's specific bit is 1,
I.e bit 4, 5, 7(direction from left to right)
B -> 01000001
----------------
A' -> 00000000
B' -> 01001011
This is pretty simple. To set A from B only bits MASK:
Clear all bits MASK from A: D = A & ~MASK
Get only bits MASK from B: E = B & MASK
Set required bits to A: RES = D | E
In most of languages it could look like this:
final int a = 0b00001010;
final int b = 0b01000001;
final int c = 0b00011010;
int aa = (a & ~c) | (b & c);
int bb = (b & ~c) | (a & c);
System.out.format("a: %08d\n", new BigInteger(Integer.toBinaryString(aa)));
System.out.format("a: %08d\n", new BigInteger(Integer.toBinaryString(bb)));
P.S. This is only basic bit operations.
I am trying to reform a string from ascii characters. I noticed when I break down ascii it matches the number with the ascii char, this changes when I tried to do (c+=c+0) on it as seen below, I tried to revert back to the original string but it doesn't seems to work. I was wondering does the ascii number change when you append it to a string?
StringBuilder b = new StringBuilder();
char c = "e".charAt(0);
System.out.println(c); //'e'
System.out.println(c+0); //101 -ascii
b.append(c+=c+0);
char d = b.charAt(0);
System.out.println(d-=d+0); //blank
When you use + to sum a char with and int, the result will be promoted
to int.
When you use compound assignment operators +=, the result will be converted to left
operand data type(in this case, char)
This is what happens with your code:
StringBuilder b = new StringBuilder();
char c = "e".charAt(0);
System.out.println(c); //'e'
System.out.println(c+0); //101 -ascii
b.append(c+=c+0); // result of c+c+0 is int 202, it is converted to char Ê
char d = b.charAt(0); // char d = Ê
System.out.println(d-=d+0); // result of d-(d+0) is int 0, it will be converted to null
It's not clear what you're trying to accomplish, but hopefully this example helps you figure out what's going on:
public static void main(String[] args) {
StringBuilder b = new StringBuilder();
char c = "e".charAt(0);
System.out.println(c); // e
System.out.println((int) c); // 101
char doubleC = (char) (c + c);
b.append(doubleC);
char d = b.charAt(0);
System.out.println((int) d); // 202
System.out.println(d - c); // 101
System.out.println((char) (d - c)); // e
}
Whether a character is printed as a letter or its ASCII value depends on its type. You can see that (int) c casts the character to its int ASCII value. Your approach of c+0 also does this but in a less intuitive way.
You also apparently want to "undo" your modification to c, but subtracting d-d always gives you 0. You need to store your value of c and subtract that from d.
+0s don't do anything because the character is underneath a number (so it's essentially like saying 101 + 0).
d-=d+0 evaluates to d = d - d + 0, so (because we're manipulating chars) d - d = 0
If you wanted to get c from d, you'd have to do d = d - c, because 'c' is the difference between the initial and the final value.
So no, the ASCII number of a character doesn't change, you're just not doing the reverse calculation as you should be.
It's like saying: x + y = z,
and then wondering why z - z != y.
You should be doing: z - x = y
#Edit
To add to your comment under pkpnd's answer - if you have only String b to work with, you'd still need to know the difference (i.e. by how much you increased/decreased the number) to reverse to the original chars.
I don't understand what is this doCalculatePi means or does, in the following example:
public static double doCalculatePi(final int sliceNr) {
final int from = sliceNr * 10;
final int to = from + 10;
final int c = (to << 1) + 1;
double acc = 0;
for (int a = 4 - ((from & 1) << 3), b = (from << 1) + 1; b < c; a = -a, b += 2) {
acc += ((double) a) / b;
}
return acc;
}
public static void main(String args[]){
System.out.println(doCalculatePi(1));
System.out.println(doCalculatePi(2));
System.out.println(doCalculatePi(3));
System.out.println(doCalculatePi(4));
System.out.println(doCalculatePi(10));
System.out.println(doCalculatePi(100));
}
I have printed the values to understand what the results are but I still have no clue what this code calculates. The conditions inside the loop are not clear.
<< means left shift operation, which shifts the left-hand operand left by the number of bits specified by the right-hand operand (See oracle docs).
Say, you have a decimal value, 5 which binary representation is 101
Now for simplicity, consider,
byte a = (byte)0x05;
Hence, the bit representation of a will be,
a = 00000101 // 1 byte is 8 bit
Now if you left shift a by 2, then a will be
a << 2
a = 00010100 //shifted place filled with zero/s
So, you may now understand that, left shift a by 3 means
a << 3
a = 00101000
For better understanding you need to study Bitwise operation.
Note, you are using int instead of byte, and by default, the int data type is a 32-bit signed integer (reference here), so you have to consider,
int a = 5;
in binary
a << 3
a = 00000000 00000000 00000000 00101000 // total 32 bit
My guess is that it approximates PI with
PI = doCalculatePi(0)+doCalculatePi(1)+doCalculatePi(2)+...
Just a guess.
Trying this
double d = 0;
for(int k = 0; k<1000; k++) {
System.out.println(d += doCalculatePi(k));
}
gives me
3.0418396189294032
3.09162380666784
3.1082685666989476
[...]
3.1414924531892394
3.14149255348994
3.1414926535900394
<< is the Bitshift operator.
Basically, every number is represented as a series of binary digits (0's and 1's), and you're shifting each of those digits to the left by however many places you indicate. So for example, 15 is 00001111 and 15 << 1 is 00011110 (or 30), while 15 << 2 is (00111100) which is 60.
There's some special handling that comes into play when you get to the sign bit, but you should get the point.
i want to replace Least significant bits with the given array...
1st input
01001100
00001000
10101010
01010100
11110110
2nd input
0
1
1
1
0
output
01001100
00001001
10101011
01010101
11110110
try this (using java 7)
int [] i = {0b01001100,
0b00001000,
0b10101010,
0b01010100,
0b11110110 };
int [] j = {0b0,
0b1,
0b1,
0b1,
0b0 };
for (int k = 0; k < i.length ; ++k){
i[k] = (i[k] >> 1) << 1; // this sets the last bit to zero
i[k] = i[k] | j[k]; // Now you can OR to get replace with the proper value
}
for(int k : i)
System.out.printf("%8s\n",Integer.toBinaryString(k));
System.out.println("----------");
I'm breaking my head over this :
for(i=0; i<message.length(); i++) {
int c = passkey.charAt(i % passkey.length());
int d = message.charAt(i);
c = c & (1 << bit);
result = result + (char)(c ^ d);
}
I know that LyJwNh9iPil3 (message) translates to ENCRYPTED (result). What I can't figure out, is what the used passkey should be. Currently, I'm stuck at :
L = 76
E = 69
so result char = 69, so c must be 69^(1/76) = 1,05729... But that is AFTER the x-th few bits are chewed off, and after the division by the password length.
I believe I will never be able to solve this, the path I'm going. Can you confirm that? The number of letters in the message and the result is different, right?
You are wrong here:
69^(1/76) = 1,05729..
^ is bitwise XOR, not power.