added fizzbuzz chapter

This commit is contained in:
Perry Kivolowitz 2022-06-09 20:17:58 -05:00
parent 94220f9837
commit 9c8ca24a6c
4 changed files with 111 additions and 55 deletions

View file

@ -10,6 +10,8 @@
"iostream", "iostream",
"memcpy", "memcpy",
"pseudocode", "pseudocode",
"stringstream",
"strncpy",
"struct", "struct",
"structs" "structs"
], ],

View file

@ -53,6 +53,7 @@ the 64 bit ARM Instruction Set Architecture (ISA).
| 5 | [Interlude - Load and Store](./section_1/regs/ldr.md) | | 5 | [Interlude - Load and Store](./section_1/regs/ldr.md) |
| 6 | [Calling and Returning From Functions](./section_1/funcs/README.md) | | 6 | [Calling and Returning From Functions](./section_1/funcs/README.md) |
| 7 | [Passing Parameters To Functions](./section_1/funcs/README2.md) | | 7 | [Passing Parameters To Functions](./section_1/funcs/README2.md) |
| 8 | [FizzBuzz - a Complete Program](./section_1/fizzbuzz/README.md) |
## Section 2 - Stuff ## Section 2 - Stuff

View file

@ -0,0 +1,51 @@
# Section 1 / Chapter 8 / FizzBuzz
In this chapter we build the classic tech interview question: FizzBuzz.
The idea is simple. Write a program that enumerates the integers from 0 to some stopping value, perhaps 100.
For each integer:
* If it is a multiple of 3, print Fizz
* If it is a multiple of 5, print Buzz
* If it is a multiple of both 3 *and* 5, print FizzBuzz
* Otherwise, if none of the above applies, print the integer.
The interviewer's hope is that you get twisted in knots trying
to navigate the case where the integer is a multiple of both 3 and
5. There are many ways to solve this challenge.
One way might be to test for being a multiple of 15 *first* and print
FizzBuzz if true. Then test against 3 and then against 5.
Another way is to accumulate the correct out by testing against 3 and
adding Fizz to a buffer. Then test against 5 and if appropriate append
Buzz to the buffer. Either the buffer was empty, in which case you get
Buzz alone - or it already contained Fizz in which case the buffer now
contains FizzBuzz. Finally, if *anything* is in the buffer, cause the
buffer to be printed and append a new line.
In C++, the buffer could be a C++ string or a stringstream. In C
you might think that you must resort to using an array of `char` to
act as the buffer, filling it with `strncpy` or some such nonsense.
But you don't have to bother! `printf` is a buffered output stream.
It won't print anything until it encounters a new line character.
In this program, we'll use this to buffer up either Fizz, Buzz or
both then as indicated above, we'll end with a new line and BAM -
whatever was in the `printf` buffer gets sent to the console.
[Here is a video](https://youtu.be/aJSGTIxu4ik) where we walk through
the process of writing FizzBuzz from scratch in ARM 64 bit assembly
language.
[Here is the source code](./fizzbuzz.s).
The video is long but there is much benefit to be had by watching
and listening to another person's process as they write the code.
**AND especially** listening and watching to them debug when
things go wrong!

View file

@ -1,91 +1,93 @@
/* Perry Kivolowitz .global main
CSC3510 .text
*/ .align 2
.global main
.text
.align 2
/* FizzBuzz - a classic interview question. /* FizzBuzz - a classic interview question.
Count from 0 to n (let's make it 100). Count from 0 to n (let's make it 100).
If the value is divisible by 3, print Fizz If the value is divisible by 3, print Fizz
If the value is divisible by 5, print Buzz If the value is divisible by 5, print Buzz
If the value is divisible by both 3 and 5, print FizzBuzz If the value is divisible by both 3 and 5, print FizzBuzz
Otherwise, print the number. Otherwise, print the number.
*/ */
/* Bible: /* Bible:
x20 counter x20 counter
w21 bool that says whether or not I have printed anything w21 bool that says whether or not I have printed anything
*/ */
/* mod(a, b) - implements a % b /* mod(a, b) - implements a % b
integer divide a by b - for example - 5 % 3 would need 5 // 3 yielding 1 a comes to us in x0
multiply result by b - 1 * 3 is 3 b comes to us in x1
subtract result from a - 5 - 3 yielding 2 and that's our return value. method:
integer divide a by b - for example - 5 % 3
would need 5 // 3 yielding 1
multiply result by b - 1 * 3 is 3
subtract result from a - 5 - 3 yielding 2
and that's our return value.
*/ */
mod: sdiv x2, x0, x1 // x2 gets a // b mod: sdiv x2, x0, x1 // x2 gets a // b
msub x0, x2, x1, x0 // x0 gets a - a // b * b msub x0, x2, x1, x0 // x0 gets a - a // b * b
ret ret
main: stp x20, x30, [sp, -16]! main: stp x20, x30, [sp, -16]!
str x21, [sp, -16]! str x21, [sp, -16]!
mov x20, xzr mov x20, xzr
1: cmp x20, 100 1: cmp x20, 100
bge 99f bge 99f
mov w21, wzr mov w21, wzr
// Test for divisible by 3 // Test for divisible by 3
mov x0, x20 mov x0, x20
mov x1, 3 mov x1, 3
bl mod bl mod
cbnz x0, 5f cbnz x0, 5f
// If we get here, the counter was divisible by 3 // If we get here, the counter was divisible by 3
ldr x0, =fizz ldr x0, =fizz
bl printf bl printf
add w21, w21, 1 add w21, w21, 1
5: mov x0, x20 5: mov x0, x20
mov x1, 5 mov x1, 5
bl mod bl mod
cbnz x0, 10f cbnz x0, 10f
// If we get here, the counter was divisible by 5 // If we get here, the counter was divisible by 5
ldr x0, =buzz ldr x0, =buzz
bl printf bl printf
add w21, w21, 1 add w21, w21, 1
10: cbz w21, 20f 10: cbz w21, 20f
// If we get here, it means that we have printed // If we get here, it means that we have printed
// something (either fizz, or buzz or fizzbuzz) // something (either fizz, or buzz or fizzbuzz)
// so all we need now is a new line // so all we need now is a new line
ldr x0, =nl ldr x0, =nl
bl puts bl puts
b 80f b 80f
20: // If we get here, the counter was neither a 20: // If we get here, the counter was neither a
// multiple of 3 nor of 5. Therefore, we need // multiple of 3 nor of 5. Therefore, we need
// to print the counter itself. // to print the counter itself.
ldr x0, =fmt ldr x0, =fmt
mov x1, x20 mov x1, x20
bl printf bl printf
80: add x20, x20, 1 80: add x20, x20, 1
b 1b b 1b
99: ldr x21, [sp], 16 99: ldr x21, [sp], 16
ldp x20, x30, [sp], 16 ldp x20, x30, [sp], 16
mov w0, wzr mov w0, wzr
ret ret
.data .data
fizz: .asciz "Fizz" fizz: .asciz "Fizz"
buzz: .asciz "Buzz" buzz: .asciz "Buzz"
nl: .asciz "" nl: .asciz ""
fmt: .asciz "%ld\n" fmt: .asciz "%ld\n"
.end .end