Reputation: 187
I am trying to perform a wrap around of the ASCII alphabet characters in order to perform a shift from a key. For example, if the key is 2 then shift the letter A
to become C
. But, how do I wrap around Z
in order to get to B
using modulus arithmetic?
I am trying to implement the following formula:
ci = (pi + key) % 26;
Where ci
is the i
th ciphered letter and pi
is the i
th letter to be ciphered.
Upvotes: 0
Views: 3249
Reputation: 153527
Deeper
ci = ((pi - 'A' + key) % 26) + 'A';
as well answered by @Sourav Ghosh generates the expected encoded A-Z when key
is non-negative and not too large. It reduces pi
with - 'A'
so the value is in the [0...25]
range and the re-offsets it after the %
calculation.
To work for the full int
range of key
takes a little more code.
Reduce key
range [INT_MIN...INT_MAX]
with the functional equivalent range of [-25 ... 25]
with key % 26
. This step is important to prevent int
overflow with pi - 'A' + key
. This can be done once if a number of letters need encoding.
Add 26. This insures negative keys are moved to positive ones.
ci = ((pi - 'A' + key%26 + 26) % 26 ) + 'A';
Note: In C, %
is not the mod operator, but the remainder operator. Functional differences occur with a%b
when a
and/or b
are negative. ref
Upvotes: 0
Reputation: 89
Others have already shown the basic concept of subtracting the offset of ASCII letters, but you have to be careful in when crossing from capital to non capital letters, as there are some symbols in between which I guess you want to avoid. I have added some logic that enables negative shifts and keeps the letter within capital letter or non capital letter space and tests whether it is a letter at all.
#include <stdio.h>
#define ASCII_CAP_LETTER_OFFS 65
#define ASCII_LETTER_OFFS 97
#define NUM_OF_LETTERS 26
char shift_letter (char letter, short shift)
{
char ci;
short shift_lcl = shift % NUM_OF_LETTERS;
if (shift_lcl >= 0)
{ // shift in positive direction
}
else
{ // shift in negative direction
shift_lcl = NUM_OF_LETTERS + shift_lcl;
}
if (letter >= ASCII_CAP_LETTER_OFFS && letter < ASCII_CAP_LETTER_OFFS + NUM_OF_LETTERS)
{// its a capital letter
ci =
(letter + shift_lcl - ASCII_CAP_LETTER_OFFS) % NUM_OF_LETTERS +
ASCII_CAP_LETTER_OFFS;
}
else if (letter >= ASCII_LETTER_OFFS && letter < ASCII_LETTER_OFFS + NUM_OF_LETTERS)
{// its a non capital letter
ci =
(letter + shift_lcl - ASCII_LETTER_OFFS) % NUM_OF_LETTERS +
ASCII_LETTER_OFFS;
}
else
{
printf ("This was not a letter!\n");
ci = 0;
}
return ci;
}
int main ()
{
char test_letter = 'a';
short test_shift = -53;
char shifted_letter = 0;
shifted_letter = shift_letter (test_letter, test_shift);
printf("%c + %d = %c", test_letter, test_shift, shifted_letter);
}
Upvotes: 2
Reputation: 134336
I believe you need to work with "relative" values, rather than absolute values.
Use something like
ci = ((pi - 'A' + key) % 26 ) + 'A';
Character integer constants stores the encoded values, in this case, ASCII. Here, 'A'
starts from an offset (decimal value of 65), not from 0. So, before you can wrap the result using a % 26
operation, you need to get that offset out. Once the calculation is done, add the offset back to get the proper ASCII representation.
Upvotes: 2