Как использовать арифметику по модулю для реализации шифра Цезаря
Я пытаюсь выполнить обтекание символов алфавита ASCII, чтобы выполнить переход от клавиши. Например, если ключ 2, сдвиньте букву A
становиться C
, Но как мне обернуть Z
чтобы добраться до B
используя модуль арифметики?
Я пытаюсь реализовать следующую формулу:
ci = (pi + key) % 26;
куда ci
это i
зашифрованное письмо и pi
это i
это письмо должно быть зашифровано.
4 ответа
Другие уже продемонстрировали основную концепцию вычитания смещения букв ASCII, но вы должны быть осторожны при переходе от заглавных букв к заглавным, поскольку между ними есть некоторые символы, которые, я думаю, вы хотите избежать. Я добавил некоторую логику, которая допускает отрицательные сдвиги и удерживает букву в пределах заглавной или не заглавной буквы и проверяет, является ли она буквой вообще.
#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);
}
Я считаю, что вам нужно работать с "относительными" значениями, а не с абсолютными значениями.
Используйте что-то вроде
ci = ((pi - 'A' + key) % 26 ) + 'A';
Символьные целочисленные константы хранят закодированные значения, в данном случае ASCII. Вот, 'A'
начинается со смещения (десятичное значение 65), а не с 0. Итак, перед тем как вы можете обернуть результат, используя % 26
операция, вы должны получить это смещение. После завершения вычисления добавьте смещение назад, чтобы получить правильное представление ASCII.
Глубже
ci = ((pi - 'A' + key) % 26) + 'A';
а также ответ @Sourav Ghosh генерирует ожидаемый закодированный AZ, когда key
неотрицателен и не слишком велик. Это уменьшает pi
с - 'A'
так что значение в [0...25]
диапазон и смещает его после %
расчет.
Работать по полной int
диапазон key
занимает немного больше кода.
уменьшить
key
спектр[INT_MIN...INT_MAX]
с функциональным эквивалентным диапазоном[-25 ... 25]
сkey % 26
, Этот шаг важен для предотвращенияint
переполнениеpi - 'A' + key
, Это можно сделать один раз, если нужно закодировать несколько букв.Добавьте 26. Это гарантирует, что отрицательные ключи будут перемещены в положительные.
ci = ((pi - 'A' + key%26 + 26) % 26 ) + 'A';
Примечание: в С, %
это не оператор мода, а оператор остатка. Функциональные различия происходят с a%b
когда a
и / или b
отрицательны. ссылка
Сурав Гхош уже ответил на ваш вопрос.
Но это еще один способ сделать это.
Случай 1:
#include<stdio.h>
int main()
{
char pi = 'Z';
char key = 2;
char offset = pi+key;
char ci =('A'+(offset%'A')%26);
printf("%c",ci);
}
Выход:
В
Вариант 2:
#include<stdio.h>
int main()
{
char pi = 'Z';
char key = 0;
char offset = pi+key;
char ci =('A'+(offset%'A')%26);
printf("%c",ci);
}
Выход:
Z
Вопрос 3:
#include<stdio.h>
int main()
{
char pi = 'Z';
char key = -1;
char offset = pi+key;
char ci =('A'+(offset%'A')%26);
printf("%c",ci);
}
Выход:
Y