0

Background

This question is inspired by The Caesar Cipher. Given a modified ASCII value i where i > 122 or i < 97, the goal is to find the char represented by its value. For example, since 'z' value is 122, then 123 references 'a', as well as 149 and 97 +- 26n.

Goal

The function calc_chr should calculate shifted ASCII values while staying inside the scope of the abc, i.e. [97, 122] decimal.

Clear Example

let 'x' be 120
let new_val be 'x' + 5 -->125
calc_chr(new_val) is equal to 'c'

The function returns 'c', as a result of shifting 'x' 5 times: x -> y, z, a, b, c.

Workaround

The workaround isn't efficient.

while new_val > 122:
    new_val -= 26
while new_val < 97:
    new_val += 26

The desired solution, if exists, is a calculation (not a loop).

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Ori David
  • 332
  • 3
  • 13

2 Answers2

4

It's not really clear what you actually want to do. My understanding is you want to type in an artificial number and then have it transformed into the from 97 to 122 (both included in the interval).

Easiest way would be:

number = input('Your number: ')
mod_number = ((number - 97) % 26) + 97
print(number, chr(number))

That way you type in a number, if it is between 97 and 122 included, then it will be kept. Otherwise it will be moved into that interval. So if you type in 123 you will end up with 97 and if you hand over 96 you will end up with 122.

Ture
  • 76
  • 2
1

You want the following ASCII mapping:

                            a-z
0-18, 19-44, 45-70, 71-96, 97-122, 123-148, 149-174, 175-200, 201-226, 227-252, 253-255
h-z    a-z    a-z    a-z    a-z      a-z      a-z      a-z      a-z      a-z      a-c

\--------- 1 -------------------/
                           \---------------------------- 2 ---------------------------/

For most programming languages (where the sign of the remainder is the sign of the dividend), two different formulas could be used:

  1. For all numbers in the range 0 to 122 use:

     r = 122 - ((122 - n) % 26)
    
  2. For all numbers in the range 97 to 255 use:

     r = ((n - 97) % 26) + 97
    

However, because the remainder does not change if we add a multiple of the divider to the dividend, we can add 4 times 26 and avoid having to deal with a negative dividend altogether.

    r = ((n - 97) % 26) + 97
 => r = ((n - 97 + (4 * 26)) % 26) + 97
<=> r = ((n - 97 + 104) % 26) + 97
<=> r = ((n + 7) % 26) + 97       ; This will work no matter how '%' functions

Now in Python, because of how the % operator functions, we can get by with this one formule:

r = ((n - 97) % 26) + 97

A very fast alternative defines a 256-byte array and then uses the calculated number as an offset in this array, fetching the result at once.

Below is what it could look like in assembly (MASM):

; On input AL register is number n=[0,255]
mov bx, offset array
xlatb
; On output AL register is number r=[97,122]         ; ["a","z"]

...

array db 'hijklmnopqrstuvwxyz'
      db 9 dup ('abcdefghijklmnopqrstuvwxyz')
      db 'abc'

And in Python it becomes

s[n]

with n ranging from 0 to 255 and using a 256-byte string s

s = ("hijklmnopqrstuvwxyz"
     "abcdefghijklmnopqrstuvwxyz"
     "abcdefghijklmnopqrstuvwxyz"
     "abcdefghijklmnopqrstuvwxyz"
     "abcdefghijklmnopqrstuvwxyz"
     "abcdefghijklmnopqrstuvwxyz"
     "abcdefghijklmnopqrstuvwxyz"
     "abcdefghijklmnopqrstuvwxyz"
     "abcdefghijklmnopqrstuvwxyz"
     "abcdefghijklmnopqrstuvwxyz"
     "abc"
    )
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • Thank you! For some reason `r = ((n - 97) % 26) + 97` for `n=95` returns `y`, which is correct. Am I missing something? How a negative `mod` works? – Ori David Jan 25 '21 at 20:52
  • You're not supposed to use that formula for `n=95`. That's a value for which you need to use the other formula `r = 122 - ((122 - n) % 26)`. Normally -2 % 26 would have to return -2, the remainder from dividing by 26. – Sep Roland Jan 25 '21 at 20:58
  • Yet in python `(-2) % 26` returns `24` for some reason. – Ori David Jan 25 '21 at 21:06
  • 1
    Apparently Python chooses to do things differently than most other programming languages! See https://stackoverflow.com/questions/3883004/the-modulo-operation-on-negative-numbers-in-python. To be honest, I did not see that the question was tagged [tag:python]... – Sep Roland Jan 25 '21 at 21:07