2

If c is the numerical value of an uppercase character (i.e. B is 66) and for the sake of argument, k is a key value of 2? I'm new to programming and don't understand how the modulo works in this. I know it takes the value of the remainder, but then wouldn't it simplify like this?

c = B = 66
k = 2
I imagine the result should be 'D'

(66 - 65 +2)%26 +65 
(3)%26 +65 
0 + 65 
65 = 'A'

I must not understand the way % works.

noggy
  • 149
  • 1
  • 2
  • 10
  • Possible duplicate of [Trying to get the remainder from modulus but having some troubles - in C](http://stackoverflow.com/questions/26682492/trying-to-get-the-remainder-from-modulus-but-having-some-troubles-in-c) – Jongware Oct 03 '15 at 00:38
  • 1
    It is a dumb obfuscation. Use character constants! – too honest for this site Oct 03 '15 at 01:50

4 Answers4

3

Key Fact - The ASCII code of the letter"A" is 65.

Here is how your cypher works - the original expression in the question title.

  1. Take the ASCII value of a letter, subtract the value of "A" from it giving you a 0 based number.
  2. Add the key value to this number shifting it by k places.
  3. Now divide the number you got above by 26, discard the quotient and use the remainder. This is the modulo operator %. This always keeps you numbers in the 0-25 range, since dividing by 26 will never a have a remainder great than 25.
  4. Add 65 to it to convert it into an "encrypted" uppercase letter.

This allows the key to be ANY number and still keeps the "encrypted" output within the ASCII range of A-Z.

You are interpreting the % operator as division. In reality, it's modulo or forget-the-quotient-I want-the-remainder operator.

Example

  1. 0%2 is 0
  2. 1%2 is 1
  3. 2%2 is 0
  4. 3%2 is 1

And so on. Modulo is cyclic.

Prashant
  • 1,002
  • 13
  • 29
1

Modulus is not int division. Modulus gives you the remainder of a division, so 3 / 26 is 0 with a remainder of 3. Therefore, 3 % 26 is 3.

adamsuskin
  • 547
  • 3
  • 16
0

3 % 26 is 3, not 0. Modulus is the remainder. Think of modulus 12 on a clock. If it is ten o'clock, and you add 4 hours, 10 + 4 = 14. But on the clock, the hand now points to 2, not 14. No matter how many hours you add, the hand always points to a number from 1 to 12. This is how modulus works.

10 + 4 = 14

14 % 12 = 2 (14 divided by 12 is 1 with remainder 2)

10 + 100 = 110

110 % 12 = 4 (110 divided by 12 is remainder 4)

If it is 10 o'clock, and you wait 100 hours, the hand now points to 4.

(Using the remainder of a division, dividing by 12 always gives a number from 0 to 11, so think of 12 o'clock as 0 o'clock.)

Jim Flood
  • 8,144
  • 3
  • 36
  • 48
0

((c - 65 + k) % 26) + 65) works, but is non portable and unnecessarily obfuscated.

65 is the ASCII code for 'A' the character constant representing the letter A. c - 65 or better c - 'A' evaluates to the distance of the uppercase letter stored in c from A, hence 1 for the letter B.

Adding k operates a shift in the alphabet, but can produce offsets greater than 25, hence the modulo operation to compute the remainder of the division by 26. (c - 65 + k) % 26 gives the offset if the encoded letter.

Adding 65 or more appropriately 'A' converts the offset back to an uppercase letter.

This expression makes the silent assumption that all uppercase letters are consecutive in the execution character set, which is true for ASCII, but not for older character sets such as EBCDIC.

Note also that the above expressions only work for positive values of k. If k is negative, the result of (c - 'a' + k) % 26 + 'a' may be negative too, hence k should be changed to a positive value first with this code:

    k = k % 26;
    if (k < 0)
        k = k + 26;

Here is a more readable alternative:

char encode_letter(char c, int k) {
    k = k % 26;
    if (k < 0)
        k = k + 26;

    if (c >= 'A' && c <= 'Z')
        return (c - 'A' + k) % 26 + 'A';
    else
    if (c >= 'a' && c <= 'a')
        return (c - 'a' + k) % 26 + 'a';
    else
        return c;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189