Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C++ numbers #169

Merged
merged 2 commits into from
Jul 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
- [last-will](./last-will/README.md)
- [log-levels](./log-levels/README.md)
- [raindrops](./raindrops/README.md)
- [freelancer-rates](./freelancer-rates/README.md)
21 changes: 21 additions & 0 deletions cpp/freelancer-rates/.exercism/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"authors": [
"vaeng"
],
"files": {
"solution": [
"freelancer_rates.cpp"
],
"test": [
"freelancer_rates_test.cpp"
],
"exemplar": [
".meta/exemplar.cpp"
]
},
"forked_from": [
"elixir/freelancer-rates"
],
"icon": "freelancer-rates",
"blurb": "Learn about integers and floating point numbers by helping a freelancer communicate with a project manager about billing."
}
1 change: 1 addition & 0 deletions cpp/freelancer-rates/.exercism/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"track":"cpp","exercise":"freelancer-rates","id":"f65aae8584e743e4a95c7f3a0dd0fd63","url":"https://exercism.org/tracks/cpp/exercises/freelancer-rates","handle":"vpayno","is_requester":true,"auto_approve":false}
66 changes: 66 additions & 0 deletions cpp/freelancer-rates/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Basic CMake project
cmake_minimum_required(VERSION 3.5.1)

# Get the exercise name from the current directory
get_filename_component(exercise ${CMAKE_CURRENT_SOURCE_DIR} NAME)

# Name the project after the exercise
project(${exercise} CXX)

# Get a source filename from the exercise name by replacing -'s with _'s
string(REPLACE "-" "_" file ${exercise})

# Implementation could be only a header
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.cpp)
set(exercise_cpp ${file}.cpp)
else()
set(exercise_cpp "")
endif()

# Use the common Catch library?
if(EXERCISM_COMMON_CATCH)
# For Exercism track development only
add_executable(${exercise} ${file}_test.cpp $<TARGET_OBJECTS:catchlib>)
elseif(EXERCISM_TEST_SUITE)
# The Exercism test suite is being run, the Docker image already includes a
# pre-built version of Catch.
find_package(Catch2 REQUIRED)
add_executable(${exercise} ${file}_test.cpp)
target_link_libraries(${exercise} PRIVATE Catch2::Catch2WithMain)
# When Catch is installed system wide we need to include a different header,
# we need this define to use the correct one.
target_compile_definitions(${exercise} PRIVATE EXERCISM_TEST_SUITE)
else()
# Build executable from sources and headers
add_executable(${exercise} ${file}_test.cpp test/tests-main.cpp)
endif()

set_target_properties(
${exercise}
PROPERTIES CXX_STANDARD 17
CXX_STANDARD_REQUIRED OFF
CXX_EXTENSIONS OFF)

set(CMAKE_BUILD_TYPE Debug)

if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(GNU|Clang)")
set_target_properties(
${exercise} PROPERTIES COMPILE_FLAGS "-Wall -Wextra -Wpedantic -Werror")
endif()

# Configure to run all the tests?
if(${EXERCISM_RUN_ALL_TESTS})
target_compile_definitions(${exercise} PRIVATE EXERCISM_RUN_ALL_TESTS)
endif()

# Tell MSVC not to warn us about unchecked iterators in debug builds
if(${MSVC})
set_target_properties(${exercise} PROPERTIES COMPILE_DEFINITIONS_DEBUG
_SCL_SECURE_NO_WARNINGS)
endif()

# Run the tests on every build
add_custom_target(
test_${exercise} ALL
DEPENDS ${exercise}
COMMAND ${exercise})
55 changes: 55 additions & 0 deletions cpp/freelancer-rates/HELP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Help

## Running the tests

Running the tests involves running `cmake -G` and then using the build command appropriate for your platform.
Detailed instructions on how to do this can be found on the [Running the Tests](https://exercism.io/tracks/cpp/tests) page for C++ on exercism.io.

## Passing the Tests

Get the first test compiling, linking and passing by following the [three
rules of test-driven development](http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd).
Create just enough structure by declaring namespaces, functions, classes,
etc., to satisfy any compiler errors and get the test to fail. Then write
just enough code to get the test to pass. Once you've done that,
uncomment the next test by moving the following line past the next test.

```C++
#if defined(EXERCISM_RUN_ALL_TESTS)
```

This may result in compile errors as new constructs may be invoked that
you haven't yet declared or defined. Again, fix the compile errors minimally
to get a failing test, then change the code minimally to pass the test,
refactor your implementation for readability and expressiveness and then
go on to the next test.

Try to use standard C++11 facilities in preference to writing your own
low-level algorithms or facilities by hand.

## Submitting your solution

You can submit your solution using the `exercism submit freelancer_rates.cpp` command.
This command will upload your solution to the Exercism website and print the solution page's URL.

It's possible to submit an incomplete solution which allows you to:

- See how others have completed the exercise
- Request help from a mentor

## Need to get help?

If you'd like help solving the exercise, check the following pages:

- The [C++ track's documentation](https://exercism.org/docs/tracks/cpp)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)

Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.

To get help if you're having trouble, you can use one of the following resources:

- [`c++-faq` tag on StackOverflow](https://stackoverflow.com/tags/c%2b%2b-faq/info)
- [C++ FAQ from isocpp.com](https://isocpp.org/faq)
- [CppReference](http://en.cppreference.com/) is a wiki reference to the C++ language and standard library
- [C traps and pitfalls](http://www.slideshare.net/LegalizeAdulthood/c-traps-and-pitfalls-for-c-programmers) is useful if you are new to C++, but have programmed in C
24 changes: 24 additions & 0 deletions cpp/freelancer-rates/HINTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Hints

## General

- Browse the [`cmath` reference][cmath-reference] to learn about common mathematical operations and transformations that work with `doubles`.

## 1. Calculate the daily rate given an hourly rate

- Basic arithmetic operations where one argument is an `int`, and the other is a `double`, will return a `double`.

## 2. Calculate a discounted price

- Basic arithmetic operations where one argument is an `int`, and the other is a `double`, will return a `double`.

## 3. Calculate the monthly rate, given an hourly rate and a discount

- There is a [function in the `cmath` header][cmath-ceil] for rounding up.

## 4. Calculate the number of workdays given a budget, hourly rate, and discount

- Casting a `double` to an `int` will truncate the number at the decimal point.

[cmath-reference]: https://en.cppreference.com/w/cpp/header/cmath
[cmath-ceil]: https://en.cppreference.com/w/cpp/numeric/math/ceil
23 changes: 23 additions & 0 deletions cpp/freelancer-rates/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.PHONY: clean
clean:
rm -rf ./build

.PHONY: test
test: clean
mkdir -pv ./build

@printf "\n"
@# each line is executed in a subshell, we have to daisy chain them so they
@# run in the build directory
cd ./build; export LDFLAGS="-lgcov --coverage" CXXFLAGS="--coverage"; cmake -DEXERCISM_RUN_ALL_TESTS=1 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -G 'Unix Makefiles' ../; if make; then printf "\n=== All Tests Passed ===\n"; else printf "\n=== Test Failure ===\n"; false; fi

.PHONY: coverage
coverage: test
@printf "\n"
find . -regextype posix-egrep -regex "^.*(tests-main|CompilerId).*[.](gcda|gcno)$$" -print -delete

@printf "\n"
find . -regextype posix-egrep -regex "^.*[.](gcda|gcno)17040"

@printf "\n"
gcovr --print-summary
124 changes: 124 additions & 0 deletions cpp/freelancer-rates/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Freelancer Rates

Welcome to Freelancer Rates on Exercism's C++ Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)

## Introduction

## Numbers

The built-in number types in C++ can be divided into integers and floating points.
Integers are whole numbers like `0`, `691`, or `-2`.
Floating point numbers are numbers with a decimal point like `6.02214076`, `0.1`, or `-1.616`.

### Integers

The following example shows the declaration and initialization of four different variables:

```cpp
int m_morales{9241}; // base 10: 0-9
int a_apaec{0x24CD}; // base 16: 0-9 and A-F
int m_gargan{0b10010000011001}; // base 2: 0-1
int b_reilly{022031}; // base 8: 0-7
// Leading with a 0 not the letter o.
```

When you assign a value to an `int` variable, you can do so directly with a literal.
A literal is a hard-coded number like `9241`.
There are different integer literals for several bases of the representation.
Decimal integer literals are the most common and use the digits `0` to `9`.
By adding a special prefix, like `0x`, it is possible to use other bases.
The example above shows the number `9421` in its four representations and prefixes.
All variables are initialized to the same value.

For more details on the different representation systems, take a look at [a small tutorial][cpp_numerical_bases].

You can use an apostrophe to separate digits for easier readability.
`9'241` is the same as `0b0100'100'0001'1001` or `92'4'1`.

### Floating-Point Numbers

The floating-point literals come in two flavors.
In addition to the intuitive `0.0024` it is possible to use its scientific notation `2.4e-3`.
The most common floating-point type is `double`.

### Arithmetic

C++ supports `+`, `-`, `*`, `/`, `(` and `)` and `%` to form expressions.
The result from the operation between two integers is also an integer.
`5 / 2` will return `2`.
When one of the involved types is a floating-point type, the result will also be of a floating-point.
`5.0 / 2` and `5 / 2.0` will return `2.5`.
`%` is the remainder operator and will return the remainder of an integer division: `5%3` is `2`.

[cpp_numerical_bases]: https://cplusplus.com/doc/hex/

## Instructions

In this exercise, you'll be writing code to help a freelancer communicate with a project manager.
Your task is to provide a few utilities to quickly calculate daily and monthly rates, optionally with a given discount.

We first establish a few rules between the freelancer and the project manager:

- The daily rate is 8 times the hourly rate.
- A month has 22 billable days.

Sometimes, the freelancer is offering to apply a discount on their daily rate (for example for their most loyal customers or not-for-profit customers).

Discounts are modeled as fractional numbers representing percentages, for example, `25.0` (25%).

## 1. Calculate the daily rate given an hourly rate

Implement a function to calculate the daily rate given an hourly rate:

```cpp
daily_rate(60)
// => 480.0
```

The returned daily rate should be of type `double`.

## 2. Calculate a discounted price

Implement a function to calculate the price after a discount.

```cpp
apply_discount(150, 10)
// => 135.0
```

The returned value should always be of type `double`, not rounded in any way.

## 3. Calculate the monthly rate, given an hourly rate and a discount

Implement a function to calculate the monthly rate, and apply a discount.

```cpp
monthly_rate(77, 10.5)
// => 12130
```

The returned monthly rate should be rounded up (take the ceiling) to the nearest integer.

## 4. Calculate the number of complete workdays given a budget, hourly rate, and discount

Implement a function that takes a budget, an hourly rate, and a discount, and calculates how many complete days of work that covers.

```cpp
days_in_budget(20'000, 80, 11.0)
// => 35
```

The returned number of days should be rounded down (take the floor) to the next integer.

## Source

### Created by

- @vaeng

### My Solution

- [my solution]()
- [run-tests](./run-tests-cpp.txt)
12 changes: 12 additions & 0 deletions cpp/freelancer-rates/compile_commands.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"directory": "/home/vpayno/git_vpayno/exercism-workspace/cpp/freelancer-rates/build",
"command": "/usr/bin/c++ -DEXERCISM_RUN_ALL_TESTS --coverage -g -Wall -Wextra -Wpedantic -Werror -std=c++17 -o CMakeFiles/freelancer-rates.dir/freelancer_rates_test.cpp.o -c /home/vpayno/git_vpayno/exercism-workspace/cpp/freelancer-rates/freelancer_rates_test.cpp",
"file": "/home/vpayno/git_vpayno/exercism-workspace/cpp/freelancer-rates/freelancer_rates_test.cpp"
},
{
"directory": "/home/vpayno/git_vpayno/exercism-workspace/cpp/freelancer-rates/build",
"command": "/usr/bin/c++ -DEXERCISM_RUN_ALL_TESTS --coverage -g -Wall -Wextra -Wpedantic -Werror -std=c++17 -o CMakeFiles/freelancer-rates.dir/test/tests-main.cpp.o -c /home/vpayno/git_vpayno/exercism-workspace/cpp/freelancer-rates/test/tests-main.cpp",
"file": "/home/vpayno/git_vpayno/exercism-workspace/cpp/freelancer-rates/test/tests-main.cpp"
}
]
8 changes: 8 additions & 0 deletions cpp/freelancer-rates/compile_flags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-std=c++17
-stdlib=libstdc++
-g
-Wall
-Wextra
-Wpedantic
-Werror
-Wno-unused-parameter
40 changes: 40 additions & 0 deletions cpp/freelancer-rates/freelancer_rates.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <cmath>

// daily_rate calculates the daily rate given an hourly rate
double daily_rate(double hourly_rate) {
const double hours = 8.0;

return hours * hourly_rate;
}

// apply_discount calculates the price after a discount
double apply_discount(double before_discount, double discount) {
const double charge_rate = (100 - discount) / 100;

return before_discount * charge_rate;
}

// monthly_rate calculates the monthly rate, given an hourly rate and a discount
// The returned monthly rate is rounded up to the nearest integer.
int monthly_rate(double hourly_rate, double discount) {
const double billable_days = 22.0;

const double monthly_cost = daily_rate(hourly_rate) * billable_days;

const double discounted_cost = apply_discount(monthly_cost, discount);

return std::ceil(discounted_cost);
}

// days_in_budget calculates the number of workdays given a budget, hourly rate,
// and discount The returned number of days is rounded down (take the floor) to
// the next integer.
int days_in_budget(int budget, double hourly_rate, double discount) {
const double daily_cost = daily_rate(hourly_rate);

const double discounted_hourly = apply_discount(daily_cost, discount);

const double days = budget / std::ceil(discounted_hourly);

return std::floor(days);
}
Loading