Lab 02: String Formatting
General Information
Submitting to the Auto-Grader
For auto-grading homework assignments in the course, we use Gradescope.
General Submission Info
When submitting files to Gradescope, you need to submit all the files you want graded at once.
You can do this in several ways:
- Select all files you want to submit and drag and drop them in the submission area when prompted.
- Browse your files when prompted by Gradescope and select all files you want to submit.
- Directly compress all the files you want to submit into a zip file (zip file name does not matter), and submit that zip file via drag-and-drop or browsing for it.
- Compress a folder containing the files you want to submit into a zip file (zip file name does not matter), and submit that zip file via drag-and-drop or browsing for it.
Gradescope will look for files with specific names, and those names are case-sensitive.
So if in the instructions we ask for a file named hello.py
,
then Gradescope will not recognize Hello.py
, hello.txt
, or hello.py.txt
.
Group Submissions
When a group of people is submitting an assignment, only one person should submit the solution.
They should then add the other members to that submission. On the Gradescope page for a submission there should be a "+ Add Group Member" button by the name in the upper-right.
This is important because if multiple people submit, our similarity checker will see identical submissions and flag that.
Unlimited attempts
You have unlimited attempts for our auto-graded assignments.
This means that you should submit early and often in order to be confident that code you are writing as you go passes all of our tests.
Academic Honesty
All work that is completed in this assignment is your own group's. You may talk to other students about the problems you are to solve, however, you may not share code in any way, except with your partner(s). What you submit must be your own group's work.
You may not use any code that is posted on the internet. If you are not sure it is in your best interest to contact the course staff. We will be using software that will compare your code to other students in the course as well as online resources. It is very easy for us to detect similar submissions and will result in a failure for the exercise or possibly a failure for the course. Please, do not do this. It is important to be academically honest and submit your work only. Please review the UMass Academic Honesty Policy and Procedures so you are aware of what this means.
Copying partial or whole solutions, obtained from other students or elsewhere, is academic dishonesty. Do not share your code with your classmates, and do not use your classmates' code. If you are confused about what constitutes academic dishonesty you should re-read the course policies. We assume you have read the course policies in detail and by submitting this project you have provided your virtual signature in agreement with these policies.
About
Labs will generally be designed to either reinforce something from class, or to teach something that may be useful for you but isn't tested in any way.
This lab is about string formatting. You will not be tested on this going forward, but it is something that is good to know.
String formatting can help you print information in a way that is more legible or easier to make sense of.
Learning Objectives
- Learn about f-Strings
- Learn to format float decimal places
- Learn to format floats in scientific notation
- Learn about variables within formatting
- Learn about string alignment
Estimated Size
3 functions:
- The first could reasonably be done with 2 lines, 1 of which is a print statement.
- The second could reasonably be done with 6 lines, 3 of which are print statements.
- The third could reasonably be done with 6 lines, 4 of which are print statements.
Preamble
String formatting is an umbrella term for techniques and machinery that lets you print things with a little more control/specificity of how they are printed.
This in generally useful making things more aesthetically pleasing and thus easier to make sense of at-a-glance.
A reference for a number of formatting options can be found here.
Below are some slides with examples of f-Strings:
Assignment
0.1. Partner up, if you'd like
Labs and assignments from here on may be done in groups of up to 3. Only the Python Setup lab had to be done alone, because we wanted to ensure everyone had the environment set up.
0.2. Make a file named format.py
(1 point)
Pretty self explanatory. Make a folder for the lab, open it in VSCode, make the file.
Now that you know about functions, most work will be in one file that has multiple functions. This is hopefully less annoying to write, and definitely easier and faster to test.
The file for this lab's work is format.py
. And don't forget author comments at the top, e.g.:
# Authors : Jared Yeager, Tim Richards
# Emails : jyeager@cs.umass.edu, richards@cs.umass.edu
# Spire IDs : 31415926, 27182818
1.1. Implement short_exp()
(1 point)
This function will take two floats, base
and exponent
.
(You may call them whatever you want, I originally just used f1
and f2
, but these names are clearer).
The function will print <base> ^ <exponent> = <result>
, where:
<base>
isbase
formatted to always give 2 decimal places<exponent>
isexponent
formatted to always give 2 decimal places<result>
isbase ** exponent
formatted to always give 2 decimal places in scientific notation (the'e'
needs to be lower case)- The
'^'
and=
should also have space around them.
For example, a call to short_exp(31.415926, 27.182818)
should print 31.42 ^ 27.18 = 4.97e+40
.
You may assume that base
is always positive.
If you would like, you may use this starter code to make sure the spacing is appropriate:
def short_exp(base:float, exponent:float) -> None:
result = base ** exponent
print(f"{base} ^ {exponent} = {result}")
short_exp(31.415926, 27.182818)
Hints
Hard to be subtle with hints for this one, so these are almost answers.
Formatting floats in decimal form: check out the Padding and truncating numbers section of the linked page.
Formatting floats in scientific notation: check out the Other number representations section of the linked page.
Testing
Stick some calls to short_exp()
in your file (outside, and below the function)
and click the play/run button in the upper-right, assuming the extensions are installed
(or open VSCode's terminal and run python3 format.py
).
The outputs should have 2 decimal places each,
and the result should be in scientific notation.
1.2 Modify short_exp()
(1 point)
Generalizing functions when you can to make them more flexible can be quite useful.
So let's generalize short_exp()
.
Modify short_exp()
to take in a third parameter, precision
, that is 2
by default.
(You may choose any name, the tests depend in it being the third parameter, not having a specific name.)
Instead of everything having 2 decimal place printed, have precision
decimal places printed.
For example, a call to short_exp(31.415926, 27.182818, 3)
should print 31.416 ^ 27.183 = 4.975e+40
.
You may assume precision
is a positive int.
Hints
Check out the Parametrized formats section of the linked page.
Testing
Same as before, except make sure to try varying values for the precision
field,
and try some calls without that third field at all (to make sure the default precision is 2).
2. Fix long_div()
(2 points)
You a given a function that currently prints long division in only a semi-formatted manner:
def long_div(dividend:int, divisor:int) -> None:
result = dividend // divisor
length_dividend = len(str(dividend)) # how long the dividend is
length_divisor = len(str(divisor)) # how long the divisor is
horizontal_bar = length_dividend * '-'
width = length_divisor + 1 + length_dividend
print(f"{result}")
print(f"{horizontal_bar}")
print(f"{divisor}|{dividend}")
long_div(12865, 415)
This function takes two ints, a dividend
and divisor
,
and should print out the long-division in a more appropriately formatted manner.
For example, a call to long_div(12865, 415)
should result in the following being printed:
31
-----
415|12865
You task is to ensure the nicely formatted version is displayed.
There are three lines of output total.
- The last of the three is the
divisor
, followed by a vertical line ('|'
), followed by thedividend
. The length of this line also determines the total width of the area alignment occurs in. (You may thus find thewidth
variable helpful.) - The second line is a right-justified series of dashes (
'-'
) that covers exactly thedividend
. thehorizontal_bar
variable already holds this, it just needs to be right-aligned. - The first line is the result of the division (note the use of integer division), right justified.
The
result
variable already holds this, it just needs to be right-aligned.
You may assume both inputs are positive integers and that the dividend
is a multiple of the divisor
.
Hints
The only new formatting tool is string alignment, which can be found under the Padding/aligning strings section.
Parametrized formats are still relevant.
Also, as intuition for the future, note where those variables came from:
- We need the result of the division the show on top (
result
). - We need a horizontal bar as long as the dividend (
horizontal_bar
), - thus we need to know the length of the dividend (
length_dividend
). - Everything needs to be right-aligned to the width (
width
), - thus we need to know the length of the dividend and divisor (
length_divisor
).
Testing
As before, just try some calls and see if they look right. Try some dividends of various length the make sure the bar on the second line adjusts correctly.
Make sure the first input to the function is multiple of the second.
I would actually pick two int
, get the product,
and pass that product and an operand to the function. For instance:
num1 = 31
num2 = 415
long_div(num1 * num2, num2)
That way you know what the answer should be and know the divisor
divides the dividend
.
3. Implement long_addsub()
(0 points)
The overall lab has been deemed too long, and this portion has been relegated to being purely extra content.
This function will take two ints, n_top
and n_bottom
say (names unimportant),
and prints a formatted long-addition/subtraction-looking final result.
A reasonable function prototype might be long_addsub(n_top:int, n_bottom:int) -> None
.
For example, a call to long_addsub(31415, 926)
would result in the following being printed:
99900
+ 314
------
100214
long_addsub(990, -1000)
would would result in the following being printed:
990
-1000
-----
- 10
There are a lot of constraints:
- The numbers are right-justified.
- The second number's sign should always be visible and used to indicate addition/subtraction.
- The addition/subtraction symbol should never have a digit from the first number directly over it (it may have a digit from the result under it though).
- If the result is negative, it's sign is left-justified.
You may assume the both numbers are integers and that the first one is positive.
Hints
In terms of formatting machinery, this is made possible by abusing some formatting options under the Signed numbers section.
The hardest part of this is figuring out what the width of the formatted region is supposed to be. Here's some more articulation:
- You need the first number and one more space (for the second number's sign) to fit
- You need the second number and its sign to fit
- You need the third number (and it's sign if it is negative) to fit
These length can be a bit trick to obtain, but calling len()
on formatted f-Strings based on these number will allow you to get length when the sign is always there, for instance.
And for ensuring all these guarantees, well, there's always the max()
function.
Testing
There are enough interesting condition here that we want to make some tests to hit all our cases of concern.
Each of those constraints may offer some test cases.
The numbers are right-justified.
Anything can be used to test this, so moving on.
The second number's sign should always be visible and used to indicate addition/subtraction.
This means we want a test where the second number is positive, and a test where it is negative.
The addition/subtraction symbol should never have a digit from the first number directly over it (it may have a digit from the result under it though).
I look at this and see the variable here being how long the first number is relative to the second. I would want to test when the first number is longer, where they are the same length, and where the second number is longer.
If the result is negative, it's sign is left-justified.
In order to check this, you need an example that has a negative result, and where that result is small enough in magnitude that the sign would be visibly moved.
Grading Scale
Below are how many points translate to what level on the 5-point scale.
1: Below Standards: 0-1 points
This is the number of points gained by only making the file.
2: Approaching Standards: 2 points
This is the number of points gained by making the file and completing only half of the first exercise.
3: Meeting Standards: 3-4 points
This is the number of points gained by making the file and completing the first exercise.
4: Exceeding Standards: 5 points
This is the number of points gained by making the file completing the first and second exercises.