Repository: exercism/python
Pull request #3287 (2022-12-25 18:17:34)

[Redesign]: numbers exercise
resolves https://github.com/exercism/python/issues/2951

meatball133: resolves #2951
meatball133: resolves #2951 

Patch:
diff --git a/concepts/numbers/.meta/config.json b/concepts/numbers/.meta/config.json
index 583a8284..7898f609 100644
--- a/concepts/numbers/.meta/config.json
+++ b/concepts/numbers/.meta/config.json
@@ -1,5 +1,5 @@
 {
-  "blurb": "There are three different types of built-in numbers: integers (\"int\"), floating-point (\"float\"), and complex (\"complex\"). Ints have arbitrary precision and floats typically have 15 decimal places of precision -- but both Int and float precision vary by host system. Complex numbers have a real and an imaginary part - each represented by floats.",
+  "blurb": "There are three different types of built-in numbers: integers (\"int\"), floating-point (\"float\"), and complex (\"complex\"). Ints have arbitrary precision and floats typically have 15 decimal places of precision -- but both int and float precision vary by host system. Complex numbers have a real and an imaginary part - each represented by floats.",
   "authors": ["Ticktakto", "Yabby1997", "limm-jk", "OMEGA-Y", "wnstj2007"],
-  "contributors": ["BethanyG", "KaiAragaki"]
+  "contributors": ["BethanyG", "KaiAragaki", "meatball133"]
 }
diff --git a/concepts/numbers/about.md b/concepts/numbers/about.md
index e746972d..1f894b0a 100644
--- a/concepts/numbers/about.md
+++ b/concepts/numbers/about.md
@@ -1,8 +1,9 @@
 # About
 
-Python has three different types of built-in numbers: integers ([`int`][int]), floating-point ([`float`][float]), and complex ([`complex`][complex]). Fractions ([`fractions.Fraction`][fractions]) and Decimals ([`decimal.Decimal`][decimals]) are also available via import from the standard library.
+Python has three different types of built-in numbers: integers ([`int`][int]), floating-point ([`float`][float]), and complex ([`complex`][complex]).
+Fractions ([`fractions.Fraction`][fractions]) and Decimals ([`decimal.Decimal`][decimals]) are also available via import from the standard library.
 
-Whole numbers (_including hex, octals and binary numbers_) **without** decimal places are identified as `ints`:
+Whole numbers including hexadecimal ([_`hex()`_][hex]), octal ([_`oct()`_][oct]) and binary ([_`bin()`_][bin]) numbers **without** decimal places are also identified as `ints`:
 
 ```python
 # Ints are whole numbers.
@@ -15,130 +16,187 @@ Whole numbers (_including hex, octals and binary numbers_) **without** decimal p
 -12
 ```
 
-Hex numbers are prefixed with `0x`:
+Numbers containing a decimal point (with or without fractional parts) are identified as `floats`:
 
 ```python
-# Hex numbers start with 0x.
->>> 0x17
-23
->>> type(0x17)
-<class 'int'>
+>>> 3.45
+3.45
+>>> type(3.45)
+<class 'float'>
 ```
 
-Octals are prefixed with a `0o`:
+## Arithmetic
+
+Python fully supports arithmetic between these different number types, and will convert narrower numbers to match their less narrow counterparts when used with the binary arithmetic operators (`+`, `-`, `*`, `/`, `//`, and `%`).
+
+All numbers (except complex) support all [arithmetic operations][arithmetic-operations], evaluated according to [operator precedence][operator precedence].
+Support for mathematical functions (beyond `+` and `-`) for complex numbers can be found in the [cmath][cmath] module.
+
+### Addition and subtraction
+
+Addition and subtraction operators behave as they do in normal math.
+If one or more of the operands is a `float`, the remaining `int`s will be converted to `float`s as well:
 
 ```python
-# Octal numbers start with a 0o.
->>> 0o446
-294
->>> type(0o446)
-<class 'int'>
+>>> 5 - 3
+2
+# The int is widened to a float here, and a float is returned.
+>>> 3 + 4.0
+7.0
 ```
 
-Binary numbers are prefixed with `0b`, and written with only zeros and ones:
+### Multiplication
+
+As with addition and subtraction, multiplication will convert narrower numbers to match their less narrow counterparts:
 
 ```python
-# Binary numbers are made up of 0s and 1s.
->>> 0b1100110
-102
->>> type(0b1100110)
-<class 'int'>
+>>> 3 * 2
+6
+
+>>> 3 * 2.0
+6.0
 ```
 
-Each of these `int` displays can be converted into the other via constructor:
+### Division
 
-```python
+Division always returns a `float`, even if the result is a whole number:
 
->>> starting_number = 1234
+```python
+>>> 6/5
+1.2
 
->>> hex(starting_number)
-'0x4d2'
+>>> 6/2
+3.0
+```
 
->>> oct(starting_number)
-'0o2322'
+### Floor division
 
->>> bin(starting_number)
-'0b10011010010'
+If an `int` result is needed, you can use floor division to truncate the result.
+Floor division is performed using the `//` operator:
 
->>> hex(0b10011010010)
-'0x4d2'
+```python
+>>> 6//5
+1
 
->>> int(0x4d2)
-1234
+>>> 6//2
+3
 ```
 
-Numbers containing a decimal point (with or without fractional parts) are identified as `floats`:
+### Modulo
+
+The modulo operator (`%`) returns the remainder of the division of the two operands:
 
 ```python
->>> 3.45
-3.45
->>> type(3.45)
-<class 'float'>
+# The result of % is zero here, because dividing 8 by 2 leaves no remainder
+>>> 8 % 2
+0
+
+# The result of % is 2 here, because 3 only goes into 5 once, with 2 left over
+>>> 5 % 3
+2
 ```
 
-Appending `j` or `J` to a number creates an _imaginary number_ -- a `complex` number with a zero real part. `ints` or `floats` can then be added to an imaginary number to create a `complex` number with both real and imaginary parts:
+Another way to look at 5 % 3:
 
 ```python
->>> 3j
-3j
->>> type(3j)
-<class 'complex'>
+>>> whole_part = int(5/3)
+1
+
+>>> decimal_part = 5/3 - whole_part
+0.6666666666666667
 
->>> 3.5+4j
-(3.5+4j)
+>>> whole_remainder = decimal_part * 3
+2.0
 ```
 
-## Arithmetic
+## Exponentiation
 
-Python fully supports arithmetic between these different number types, and will convert narrower numbers to match their less narrow counterparts when used with the binary arithmetic operators (`+`, `-`, `*`, `/`, `//`, and `%`).
-
-Python considers `ints` narrower than `floats`, which are considered narrower than `complex` numbers. Comparisons between different number types behave as if the _exact_ values of those numbers were being compared:
+Exponentiation is performed using the `**` operator:
 
 ```python
-# The int is widened to a float here, and a float is returned.
->>> 3 + 4.0
-7.0
+>>> 2 ** 3
+8
+
+>>> 4 ** 0.5
+2
+```
 
-# The int is widened to a complex number, and a complex number is returned.
->>> 6/(3+2j)
-(2+2j)
+## Conversions
 
-# Division always returns a float, even if integers are used.
->>> 6/2
+Numbers can be converted from `int` to `floats` and `floats` to `int` using the built-in functions `int()` and `float()`:
+
+```python
+>>> int(3.45)
+3
+
+>>> float(3)
 3.0
+```
 
-# If an int result is needed, you can use floor division to truncate the result.
->>> 6//2
+## Round
+
+Python provides a built-in function [`round(number, <decimal_places>)`][round] to round off a floating point number to a given number of decimal places.
+If no number of decimal places is specified, the number is rounded off to the nearest integer and will return an `int`:
+
+```python
+>>> round(3.1415926535, 2)
+3.14
+
+>>> round(3.1415926535)
 3
+```
 
-# When comparing, exact values are used.
->>> 23 == 0x17
-True
+## Priority and parentheses
 
->>> 0b10111 == 0x17
-True
+Python allows you to use parentheses to group expressions.
+This is useful when you want to override the default order of operations.
 
->>> 6 == (6+0j)
-True
+```python
+>>> 2 + 3 * 4
+14
+
+>>> (2 + 3) * 4
+20
 ```
 
-All numbers (except complex) support all [arithmetic operations][arethmetic-operations], evaluated according to [operator precedence][operator precedence]. Support for mathematical functions (beyond `+`, `-`, `/`) for complex numbers can be found in the [cmath][cmath] module.
+Python follows the [PEMDAS][pemdas] rule for operator precedence.
+This means calculations within `()` have the highest priority, followed by `**`, then `*`, `/`, `//`, `%`, `+`, and `-`:
+
+```python
+>>> 2 + 3 - 4 * 4
+-11
+
+>>> (2 + 3 - 4) * 4
+20
+
+# In the following example, the `**` operator has the highest priority, then `*`, then `+`
+# Meaning we first do 4 ** 4, then 3 * 64, then 2 + 192
+>>> 2 + 3 * 4 ** 4
+770
+```
 
 ## Precision & Representation
 
-Integers in Python have [arbitrary precision](https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic) -- the amount of digits is limited only by the available memory of the host system.
+Integers in Python have [arbitrary precision][arbitrary-precision] -- the amount of digits is limited only by the available memory of the host system.
 
-Floating point numbers are usually implemented using a `double` in C (_15 decimal places of precision_), but will vary in representation based on the host system. Complex numbers have a `real` and an `imaginary` part, both of which are represented by floating point numbers.
+Floating point numbers are usually implemented using a `double` in C (_15 decimal places of precision_), but will vary in representation based on the host system.
+Complex numbers have a `real` and an `imaginary` part, both of which are represented by floating point numbers.
 
-For a more detailed discussions of the issues and limitations of floating point arithmetic across programming langages, take a look at [0.30000000000000004.com][0.30000000000000004.com] and [The Python Tutorial][floating point math].
+For a more detailed discussions of the issues and limitations of floating point arithmetic across programming languages, take a look at [0.30000000000000004.com][0.30000000000000004.com] and [The Python Tutorial][floating point math].
 
-[int]: https://docs.python.org/3/library/functions.html#int
-[float]: https://docs.python.org/3/library/functions.html#float
-[complex]: https://docs.python.org/3/library/functions.html#complex
-[fractions]: https://docs.python.org/3/library/fractions.html
-[decimals]: https://docs.python.org/3/library/decimal.html#module-decimal
 [0.30000000000000004.com]: https://0.30000000000000004.com/
+[arbitrary-precision]: https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic
+[arithmetic-operations]: https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex
+[bin]: https://docs.python.org/3/library/functions.html#bin
 [cmath]: https://docs.python.org/3.9/library/cmath.html
-[arethmetic-operations]: https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex
-[operator precedence]: https://docs.python.org/3/reference/expressions.html#operator-precedence
+[complex]: https://docs.python.org/3/library/functions.html#complex
+[decimals]: https://docs.python.org/3/library/decimal.html#module-decimal
+[float]: https://docs.python.org/3/library/functions.html#float
 [floating point math]: https://docs.python.org/3.9/tutorial/floatingpoint.html
+[fractions]: https://docs.python.org/3/library/fractions.html
+[hex]: https://docs.python.org/3/library/functions.html#hex
+[int]: https://docs.python.org/3/library/functions.html#int
+[oct]: https://docs.python.org/3/library/functions.html#oct
+[operator precedence]: https://docs.python.org/3/reference/expressions.html#operator-precedence
+[pemdas]: https://mathworld.wolfram.com/PEMDAS.html
+[round]: https://docs.python.org/3/library/functions.html#round
diff --git a/concepts/numbers/introduction.md b/concepts/numbers/introduction.md
index c7213928..3491bc20 100644
--- a/concepts/numbers/introduction.md
+++ b/concepts/numbers/introduction.md
@@ -1,97 +1,18 @@
 # Introduction
 
-## Numbers
+Python has three different types of built-in numbers: integers ([`int`][int]), floating-point ([`float`][float]), and complex ([`complex`][complex]).
+Fractions ([`fractions.Fraction`][fractions]) and Decimals ([`decimal.Decimal`][decimals]) are also available via import from the standard library.
 
-There are three different kinds of built-in numbers in Python : `ints`, `floats`, and `complex`. However, in this exercise you'll be dealing only with `ints` and `floats`.
+Whole numbers including hexadecimal ([_`hex()`_][hex]), octal ([_`oct()`_][oct]) and binary ([_`bin()`_][bin]) numbers **without** decimal places are also identified as `ints`.
 
-### ints
+Python fully supports arithmetic between these different number types, and will convert narrower numbers to match their less narrow counterparts when used with the binary arithmetic operators (`+`, `-`, `*`, `/`, `//`, and `%`).
 
-`ints` are whole numbers. e.g. `1234`, `-10`, `20201278`.
 
-Integers in Python have [arbitrary precision][arbitrary-precision] -- the amount of digits is limited only by the available memory of the host system.
-
-### floats
-
-`floats` or `floating point numbers` contain a decimal point. e.g. `0.0`,`3.14`,`-9.01`.
-
-Floating point numbers are usually implemented in Python using a `double` in C (_15 decimal places of precision_), but will vary in representation based on the host system and other implementation details. This can create some surprises when working with floats, but is "good enough" for most situations.
-
-You can see more details and discussions in the following resources:
-
-- [Python numeric type documentation][numeric-type-docs]
-- [The Python Tutorial][floating point math]
-- [Documentation for `int()` built in][`int()` built in]
-- [Documentation for `float()` built in][`float()` built in]
-- [0.30000000000000004.com][0.30000000000000004.com]
-
-### Precision
-
-Before diving into arithmetic, it is worth thinking about what precision means. Precision is the level of exactness at which a number can be represented. An `int` is less precise than a `float` in the same way that `1` is less precise than `1.125`.
-
-## Arithmetic
-
-Python fully supports arithmetic between `ints` and `floats`. It will convert narrower numbers to match their wider (or more precise) counterparts when used with the binary arithmetic operators (`+`, `-`, `*`, `/`, `//`, and `%`). When division with `/`, `//` returns the quotient and `%` returns the remainder.
-
-Python considers `ints` narrower than `floats`. So, using a float in an expression ensures the result will be a float too. However, when doing division, the result will always be a float, even if only integers are used.
-
-```python
-# The int is widened to a float here, and a float type is returned.
->>> 3 + 4.0
-7.0
->>> 3 * 4.0
-12.0
->>> 3 - 2.0
-1.0
-# Division always returns a float.
->>> 6 / 2
-3.0
->>> 7 / 4
-1.75
-# Calculating remainders.
->>> 7 % 4
-3
->>> 2 % 4
-2
->>> 12.75 % 3
-0.75
-```
-
-If an int result is needed, you can use `//` to truncate the result.
-
-```python
->>> 6 // 2
-3
->>> 7 // 4
-1
-```
-
-To convert a float to an integer, you can use `int()`. Also, to convert an integer to a float, you can use `float()`.
-
-```python
->>> int(6 / 2)
-3
->>> float(1 + 2)
-3.0
-```
-
-## Underscores in Numeric Literals
-
-As of version 3.6, Python supports the use of underscores in numerical literals to improve readability:
-```python
-# A float with underscores
->>> dollars = 35_000_000.0
->>> print(dollars)
-35000000.0
-```
-
-The rules for underscores are outline in [pep 515][pep 515] under 'Literal Grammar' are quite dense, but essentially boil down to:
-* Underscores can only be between two digits (not at beginning or ends of numbers, or next to signs (+/-) or decimals points)
-* No consecutive underscores
-
-[arbitrary-precision]: https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic#:~:text=In%20computer%20science%2C%20arbitrary%2Dprecision,memory%20of%20the%20host%20system.
-[numeric-type-docs]: https://docs.python.org/3/library/stdtypes.html#typesnumeric
-[`int()` built in]: https://docs.python.org/3/library/functions.html#int
-[`float()` built in]: https://docs.python.org/3/library/functions.html#float
-[0.30000000000000004.com]: https://0.30000000000000004.com/
-[floating point math]: https://docs.python.org/3.9/tutorial/floatingpoint.html
-[pep 515]: https://www.python.org/dev/peps/pep-0515/
+[bin]: https://docs.python.org/3/library/functions.html#bin
+[complex]: https://docs.python.org/3/library/functions.html#complex
+[decimals]: https://docs.python.org/3/library/decimal.html#module-decimal
+[float]: https://docs.python.org/3/library/functions.html#float
+[fractions]: https://docs.python.org/3/library/fractions.html
+[hex]: https://docs.python.org/3/library/functions.html#hex
+[int]: https://docs.python.org/3/library/functions.html#int
+[oct]: https://docs.python.org/3/library/functions.html#oct
diff --git a/config.json b/config.json
index d1399f2f..c7e5b9e0 100644
--- a/config.json
+++ b/config.json
@@ -42,13 +42,21 @@
         "prerequisites": ["basics"],
         "status": "beta"
       },
+      {
+        "slug": "electric-bill",
+        "name": "Electric Bill",
+        "uuid": "b2fd556b-07a8-47d6-9811-4d847cf0c6da",
+        "concepts": ["numbers"],
+        "prerequisites": ["basics"],
+        "status": "beta"
+      },
       {
         "slug": "currency-exchange",
         "name": "Currency Exchange",
         "uuid": "1335ca33-3af0-4720-bcf2-bfa68ffc6862",
         "concepts": ["numbers"],
         "prerequisites": ["basics"],
-        "status": "beta"
+        "status": "wip"
       },
       {
         "slug": "meltdown-mitigation",
diff --git a/exercises/concept/electric-bill/.docs/hints.md b/exercises/concept/electric-bill/.docs/hints.md
new file mode 100644
index 00000000..34a6eb7a
--- /dev/null
+++ b/exercises/concept/electric-bill/.docs/hints.md
@@ -0,0 +1,30 @@
+# General
+
+Remember that you can always reuse/call previously completed functions when writing new ones.
+
+## 1. Get extra hours
+
+- This is all about calculating the _remainder_ left after whole division.
+- Take a look at [`divmod()`][divmod], and look for an operator that does something similar.
+
+## 2. Get kW value
+
+- Remember to give [`round()`][round] a number of _decimal places_, or you will get a whole number back as a result.
+
+## 3. Get kwh value
+
+- The result of dividing an `int` by a `float` is always a `float`.
+- To get only an integer value from division, use [_floor_ division][floor], which will truncate the decimal.
+
+## 4. Get efficiency
+
+- The result of dividing an `int` by a `float` is always a `float`.
+
+## 5. Get cost
+
+- It might be good to _reuse_ or call other functions you have already completed here.
+- The result of dividing an `int` by a `float` is always a `float`.
+
+[divmod]: https://docs.python.org/3/library/functions.html#divmod
+[floor]: https://docs.python.org/3/glossary.html#term-floor-division
+[round]: https://docs.python.org/3/library/functions.html#round
diff --git a/exercises/concept/electric-bill/.docs/instructions.md b/exercises/concept/electric-bill/.docs/instructions.md
new file mode 100644
index 00000000..59aed291
--- /dev/null
+++ b/exercises/concept/electric-bill/.docs/instructions.md
@@ -0,0 +1,80 @@
+# Instructions
+
+The company you work for wants to reduce their carbon footprint, so they want you to write a program to calculate the power usage and cost of running their electronics.
+
+1. Get extra hours
+
+Your employer has a program that calculates the time it takes to run different electronics.
+Currently, the time is stored in hours.
+When your employer added the hours, they noticed that the time duration was not correct.
+They want you to add 3 extra hours to the time data.
+They would also like to know how many "extra" hours there are after converting the data to "full" days (a day is 24 hours).
+The time to convert may not be in full days.
+
+Implement a function `get_extra_hours()` that accepts an integer which holds the number of hours.
+The function should make the appropriate "extra hours" adjustment, and then `return` an integer representing how many hours needs to be removed from the total to get the time in "full" days.
+
+```python
+>>> get_extra_hours(25)
+4
+```
+
+2. Get kW value
+
+Your employer wants to know the power usage of the different electronics in kW.
+kW stands for kilowatt, where watts are a unit of power.
+Kilo in the unit name is a prefix in the metric system meaning 1000.
+One kilowatt == 1000 watts.
+
+Implement a function `get_kW_value()` that accepts an integer which holds the number of watts.
+The function should then `return` the watts as kilowatts rounded to 1 decimal place.
+
+```python
+>>> get_kW_value(1150)
+1.2
+```
+
+3. Get kWh value
+
+To be able to calculate the cost of running the electronics, your employer needs to know the power usage in kWh.
+kWh stands for kilowatt-hour, where hour is a unit of time.
+One kilowatt-hour == 1000 watts used for 1 hour.
+An hour is made up of 60 minutes and a minute is made up of 60 seconds.
+One hour is equal to 3600 seconds.
+To calculate the kWh value, you must convert watts to kW, and then floor-divide the result by 3600.
+
+Implement a function `get_kWh_value()` that accepts an integer which holds the number of watts.
+The function should then `return` the kilowatt-hours as an integer.
+
+```python
+>>> get_kWh_value(5000000)
+1
+```
+
+4. Get efficiency
+
+Electronics are not 100% efficient.
+Therefore, your employer wants you to calculate the _efficiency_ of the electronics.
+To get efficiency, you must divide the power factor (_a float between 0 and 100_) by 100.
+
+Implement a function `get_efficiency()` that accepts a float that holds the power factor.
+The function should then `return` the calculated efficiency as a float.
+
+```python
+>>> get_efficiency(80)
+0.8
+```
+
+5. Get cost
+
+Your employer wants to know the cost of running the electronics.
+The cost of running the electronics is the power used multiplied by the cost per kWh.
+The power used is the power given divided by the calculated efficiency.
+
+Implement a function `get_cost(<watts>,<power_factor>,<price>)` that accepts an integer that holds the number of watts, a float that has the power factor, and a float that holds the cost per kWh.
+The function should then `return` the cost of running the electronics as a float.
+
+```python
+>>> get_cost(5000000, 80, 0.25)
+0.3125
+```
diff --git a/exercises/concept/electric-bill/.docs/introduction.md b/exercises/concept/electric-bill/.docs/introduction.md
new file mode 100644
index 00000000..719aea05
--- /dev/null
+++ b/exercises/concept/electric-bill/.docs/introduction.md
@@ -0,0 +1,172 @@
+# Introduction
+
+Python has three different types of built-in numbers: integers ([`int`][int]), floating-point ([`float`][float]), and complex ([`complex`][complex]).
+Fractions ([`fractions.Fraction`][fractions]) and Decimals ([`decimal.Decimal`][decimals]) are also available via import from the standard library.
+
+Whole numbers including hexadecimal ([_`hex()`_][hex]), octal ([_`oct()`_][oct]) and binary ([_`bin()`_][bin]) numbers **without** decimal places are also identified as `ints`:
+
+```python
+# Ints are whole numbers.
+>>> 1234
+1234
+>>> type(1234)
+<class 'int'>
+
+>>> -12
+-12
+```
+
+Numbers containing a decimal point (with or without fractional parts) are identified as `floats`:
+
+```python
+>>> 3.45
+3.45
+>>> type(3.45)
+<class 'float'>
+```
+
+## Arithmetic
+
+Python fully supports arithmetic between these different number types, and will convert narrower numbers to match their less narrow counterparts when used with the binary arithmetic operators (`+`, `-`, `*`, `/`, `//`, and `%`).
+
+### Addition and subtraction
+
+Addition and subtraction operators behave as they do in normal math.
+If one or more of the operands is a `float`, the remaining `int`s will be converted to `float`s as well:
+
+```python
+>>> 5 - 3
+2
+# The int is widened to a float here, and a float is returned.
+>>> 3 + 4.0
+7.0
+```
+
+### Multiplication
+
+As with addition and subtraction, multiplication will convert narrower numbers to match their less narrow counterparts:
+
+```python
+>>> 3 * 2
+6
+
+>>> 3 * 2.0
+6.0
+```
+
+### Division
+
+Division always returns a `float`, even if the result is a whole number:
+
+```python
+>>> 6/5
+1.2
+
+>>> 6/2
+3.0
+```
+
+### Floor division
+
+If an `int` result is needed, you can use floor division to truncate the result.
+Floor division is performed using the `//` operator:
+
+```python
+>>> 6//5
+1
+
+>>> 6//2
+3
+```
+
+### Modulo
+
+The modulo operator (`%`) returns the remainder of the division of the two operands:
+
+```python
+# The result of % is zero here, because dividing 8 by 2 leaves no remainder
+>>> 8 % 2
+0
+
+# The result of % is 2 here, because 3 only goes into 5 once, with 2 leftover
+>>> 5 % 3
+2
+```
+
+Another way to look at 5 % 3:
+
+```python
+>>> whole_part = int(5/3)
+1
+
+>>> decimal_part = 5/3 - whole_part
+0.6666666666666667
+
+>>> whole_remainder = decimal_part * 3
+2.0
+```
+
+## Round
+
+Python provides a built-in function [`round(number, <decimal_places>)`][round] to round off a floating point number to a given number of decimal places.
+If no number of decimal places is specified, the number is rounded off to the nearest integer and will return an `int`:
+
+```python
+>>> round(3.1415926535, 2)
+3.14
+
+>>> round(3.1415926535)
+3
+```
+
+## Priority and parentheses
+
+Python allows you to use parentheses to group expressions.
+This is useful when you want to override the default order of operations.
+
+```python
+>>> 2 + 3 * 4
+14
+
+>>> (2 + 3) * 4
+20
+```
+
+Python follows the [PEMDAS][pemdas] rule for operator precedence.
+This means calculations within `()` have the highest priority, followed by `**`, then `*`, `/`, `//`, `%`, `+`, and `-`:
+
+```python
+>>> 2 + 3 - 4 * 4
+-11
+
+>>> (2 + 3 - 4) * 4
+20
+
+# In the following example, the `**` operator has the highest priority, then `*`, then `+`
+# Meaning we first do 4 ** 4, then 3 * 64, then 2 + 192
+>>> 2 + 3 * 4 ** 4
+770
+```
+
+## Precision & Representation
+
+Integers in Python have [arbitrary precision][arbitrary-precision] -- the amount of digits is limited only by the available memory of the host system.
+
+Floating point numbers are usually implemented using a `double` in C (_15 decimal places of precision_), but will vary in representation based on the host system.
+Complex numbers have a `real` and an `imaginary` part, both of which are represented by floating point numbers.
+
+For a more detailed discussions of the issues and limitations of floating point arithmetic across programming languages, take a look at [0.30000000000000004.com][0.30000000000000004.com] and [The Python Tutorial][floating point math].
+
+[0.30000000000000004.com]: https://0.30000000000000004.com/
+[arbitrary-precision]: https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic
+[bin]: https://docs.python.org/3/library/functions.html#bin
+[complex]: https://docs.python.org/3/library/functions.html#complex
+[decimals]: https://docs.python.org/3/library/decimal.html#module-decimal
+[float]: https://docs.python.org/3/library/functions.html#float
+[floating point math]: https://docs.python.org/3.9/tutorial/floatingpoint.html
+[fractions]: https://docs.python.org/3/library/fractions.html
+[hex]: https://docs.python.org/3/library/functions.html#hex
+[int]: https://docs.python.org/3/library/functions.html#int
+[oct]: https://docs.python.org/3/library/functions.html#oct
+[pemdas]: https://mathworld.wolfram.com/PEMDAS.html
+[round]: https://docs.python.org/3/library/functions.html#round
diff --git a/exercises/concept/electric-bill/.meta/config.json b/exercises/concept/electric-bill/.meta/config.json
new file mode 100644
index 00000000..eca6e91c
--- /dev/null
+++ b/exercises/concept/electric-bill/.meta/config.json
@@ -0,0 +1,19 @@
+{
+  "authors": [
+    "meatball133",
+    "BethanyG"
+  ],
+  "files": {
+    "solution": [
+      "electric_bill.py"
+    ],
+    "test": [
+      "electric_bill_test.py"
+    ],
+    "exemplar": [
+      ".meta/exemplar.py"
+    ]
+  },
+  "icon": "city-office",
+  "blurb": "Learn about numbers in Python while saving your employers money on their electric bill."
+}
diff --git a/exercises/concept/electric-bill/.meta/exemplar.py b/exercises/concept/electric-bill/.meta/exemplar.py
new file mode 100644
index 00000000..230f8925
--- /dev/null
+++ b/exercises/concept/electric-bill/.meta/exemplar.py
@@ -0,0 +1,51 @@
+"""Functions to help the company calculate their power usage."""
+
+
+def get_extra_hours(hours):
+    """Return the amount of hours.
+
+    :param: hours: int - amount of hours.
+    :return: int - amount of "extra" hours.
+    """
+
+    return (hours + 3) % 24
+
+
+def get_kW_value(watts):
+    """Return the kW value of a given watt value.
+
+    :param: watts: int - watt value.
+    :return: float - kW value.
+    """
+
+    # rounds to one decimal place here
+    return round(watts / 1000, 1)
+
+
+def get_kwh_value(watts):
+    """Return the kWh value of a given watt value and hours.
+
+    :param: watts: int - watt value.
+    :param: hours: int - kilowatt hour value.
+    """
+    return get_kW_value(watts) // 3600
+
+
+def get_efficiency(power_factor):
+    """Return the efficiency calculated from the power factor.
+
+    :param: power_factor: float.
+    :return: float - efficiency.
+    """
+    return power_factor / 100
+
+
+def get_cost(watts, power_factor, price):
+    """Calculate the cost of a given kWh value, efficiency and price.
+
+    :param: watts: int - watt value.
+    :param: power_factor: float - efficiency.
+    :param: price: float - price of kWh.
+    :return: float - cost of kWh.
+    """
+    return price * (get_kwh_value(watts) / get_efficiency(power_factor))
diff --git a/exercises/concept/electric-bill/electric_bill.py b/exercises/concept/electric-bill/electric_bill.py
new file mode 100644
index 00000000..2a2dc715
--- /dev/null
+++ b/exercises/concept/electric-bill/electric_bill.py
@@ -0,0 +1,48 @@
+"""Functions to help the company calculate their power usage."""
+
+
+def get_extra_hours(hours):
+    """Return the amount of hours.
+
+    :param: hours: int - amount of hours.
+    :return: int - amount of "extra" hours.
+    """
+    pass
+
+
+def get_kW_value(watts):
+    """Return the kW value of a given watt value.
+
+    :param: watts: int - watt value.
+    :return: float - kW value.
+    """
+    pass
+
+
+def get_kwh_value(watts):
+    """Return the kWh value of a given watt value and hours.
+
+    :param: watts: int - watt value.
+    :param: hours: int - kilowatt hour value.
+    """
+    pass
+
+
+def get_efficiency(power_factor):
+    """Return the efficiency calculated from the power factor.
+
+    :param: power_factor: float.
+    :return: float - efficiency.
+    """
+    pass
+
+
+def get_cost(watts, power_factor, price):
+    """Calculate the cost of a given kWh value, efficiency and price.
+
+    :param: watts: int - watt value.
+    :param: power_factor: float - efficiency.
+    :param: price: float - price of kWh.
+    :return: float - cost of kWh.
+    """
+    pass


Test patch:
diff --git a/exercises/concept/electric-bill/electric_bill_test.py b/exercises/concept/electric-bill/electric_bill_test.py
new file mode 100644
index 00000000..d5963c98
--- /dev/null
+++ b/exercises/concept/electric-bill/electric_bill_test.py
@@ -0,0 +1,60 @@
+import unittest
+import pytest
+from electric_bill import (get_extra_hours,
+                                 get_kW_value,
+                                 get_kwh_value,
+                                 get_efficiency,
+                                 get_cost)
+
+
+class LocomotiveEngineerTest(unittest.TestCase):
+
+    @pytest.mark.task(taskno=1)
+    def test_get_extra_hours(self):
+        input_data = [25, 10, 5, 2, 1, 120, 21]
+        output_data = [4, 13, 8, 5, 4, 3, 0]
+
+        for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
+            with self.subTest(f'variation #{variant}', input_data=input_data, output_data=output_data):
+                error_msg=f'Expected: {output_data} but got a different value.'
+                self.assertEqual(get_extra_hours(input_data), output_data, msg=error_msg)
+
+    @pytest.mark.task(taskno=2)
+    def test_get_kW_value(self):
+        input_data = [1000, 2200, 2900, 900, 1160]
+        output_data = [1, 2.2, 2.9, 0.9, 1.2]
+
+        for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
+            with self.subTest(f'variation #{variant}', input_data=input_data, output_data=output_data):
+                error_msg=f'Expected: {output_data} but got a different value.'
+                self.assertEqual(get_kW_value(input_data), output_data, msg=error_msg)
+
+    @pytest.mark.task(taskno=3)
+    def test_get_kwh_value(self): 
+        input_data = (5000000, 2141241, 43252135, 5324623462, 4321512)
+        output_data = [1, 0, 12, 1479, 1]
+
+        for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
+            with self.subTest(f'variation #{variant}', input_data=input_data, output_data=output_data):
+                error_msg=f'Expected: {output_data} but got a different value.'
+                self.assertEqual(get_kwh_value(input_data), output_data, msg=error_msg)
+
+    @pytest.mark.task(taskno=4)
+    def test_get_efficiency(self): 
+        input_data = [80.0, 99.99, 0.8, 40.0]
+        output_data = [0.8, 0.9999, 0.008, 0.4]
+
+        for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
+            with self.subTest(f'variation #{variant}', input_data=input_data, output_data=output_data):
+                error_msg=f'Expected: {output_data} but got a different value.'
+                self.assertAlmostEqual(get_efficiency(input_data), output_data, msg=error_msg)
+
+    @pytest.mark.task(taskno=5)
+    def test_get_cost(self):
+        input_data = ((5000000, 80.0, 0.25), (2141241, 99.99, 2), (43252135, 0.8, 4), (4321512, 40.0, 2))
+        output_data = (0.3125, 0, 6000, 5)
+        
+        for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
+            with self.subTest(f'variation #{variant}', input_data=input_data, output_data=output_data):
+                error_msg=f'Expected: {output_data} but got a different value.'
+                self.assertEqual(get_cost(*input_data), output_data, msg=error_msg)