LMU ☀️ CMSI 2210
COMPUTER SYSTEMS ORGANIZATION
HOMEWORK #4 Due: 2018-04-12

Please work in pairs, unless you really, really don’t want to (it’s okay). Submit in a private GitHub repository. Private repositories are free for students.

  1. Write a C program that writes, to standard output, the names of the 88 piano keys and their frequencies. The program needs to actually compute the values; you cannot hardcode them. Display all frequencies with four places after the decimal point.
    $ piano_keys
    A          27.5000
    A#         29.1352
    B          30.8677
    C          32.7032
    C#         34.6478
    D          36.7081
    D#         38.8909
    .
    .
    .
    A#       3729.3101
    B        3951.0664
    C        4186.0090
    

    Your expected output should be exactly the same as the following Python script. You can use the Python script as a guide for forming your solution in C, but notice a tiny step-by-step translation is likely a bad idea, as the two languages are very different):

    piano_keys.py
    KEY_NAMES = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#']
    STEPS = len(KEY_NAMES)
    NUMBER_OF_KEYS = 88;
    INITIAL_FREQUENCY = 27.5;
    
    for i in range(NUMBER_OF_KEYS):
        key_name = KEY_NAMES[i % STEPS]
        frequency = INITIAL_FREQUENCY * (2.0 ** (i / STEPS))
        print(f'{key_name}\t{frequency:10.4f}')
    
  2. Write a C program that takes a command line argument which is the name of a piano key, and writes to standard output the major and natural minor scales for that key.
    $ piano_scales F#
    F# major: F# G# A# B  C# D# E#
    F# minor: F# G# A  B  C# D  E
    

    Your expected output should be exactly the same as the following Python script. You can use the Python script as a guide for forming your solution in C, but notice a tiny step-by-step translation is likely a bad idea, as the two languages are very different. C doesn’t have exceptions, not a direct transation of Python’s index method, just to name a couple differences (there are more):

    scales.py
    import sys
    
    KEY_NAMES = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#']
    NUMBER_OF_NOTES = len(KEY_NAMES)
    
    MAJOR_STEPS = [2,2,1,2,2,2]
    MINOR_STEPS = [2,1,2,2,1,2]
    NUMBER_OF_STEPS = len(MAJOR_STEPS)
    
    def print_scale(note_index, type, steps):
        print(f'{KEY_NAMES[note_index]:3}{type}: {KEY_NAMES[note_index]:3}', end='')
        offset = 0
        for step in steps:
            offset += step
            print(f'{KEY_NAMES[(note_index + offset) % NUMBER_OF_NOTES]:3}', end='')
        print()
    
    if __name__ == '__main__':
        if len(sys.argv) != 2:
            print("This program requires exactly one command line argument\n")
            sys.exit(1)
    
        try:
            key_index = KEY_NAMES.index(sys.argv[1].upper())
        except ValueError:
            print(f'No such key: {sys.argv[1]}')
            sys.exit(2)
    
        print_scale(key_index, "major", MAJOR_STEPS)
        print_scale(key_index, "minor", MINOR_STEPS)
    
  3. Write a C function which takes in two strings (pointers to bytes in memory with a zero at the end), and returns a new string made by joining up successive substrings of the arguments, according to the examples below.
    silly("phone", "booth")  ⇒  "pphphophonphoneboothbootboobob"
    silly("", "")  ⇒  ""
    silly("abc", "")  ⇒  "aababc"
    silly("", "abc")  ⇒  "abcaba"
    silly("too", "real")  ⇒  "ttotoorealrearer"
    
  4. Write a C function that takes in a string s and an int k and returns a newly allocated string which is the k-fold left rotation of s. For example, perfoming this operation on "doghouse" and 3 will return "housedog". More examples:
    rotate("doghouse", 0)  ⇒  "doghouse"
    rotate("doghouse", 1)  ⇒  "oghoused"
    rotate("doghouse", 2)  ⇒  "ghousedo"
    rotate("doghouse", 3)  ⇒  "housedog"
    rotate("doghouse", 4)  ⇒  "ousedogh"
    rotate("doghouse", 5)  ⇒  "usedogho"
    

    Make sure to consider inputs that are negative, zero, in the billions (or even greater).

  5. Write a C program that reads, from standard input, text encoded in UTF-32LE (where LE means "little endian"), and writes the corresponding UTF-8 to standard output. Set the return code of the process properly: 0 on success, non-zero on failure. Whenever you encounter an illegal character in the input, you can output a Unicode REPLACEMENT CHARACTER (encoded in UTF-8, of course). If any REPLACEMENT CHARACTER is ever output because of an illegal character, your program should produce a non-zero return code.