Problem understanding "currency exhange" exercise

Code Run
test_data = [(100000, 10.61, 10, 1),
             (1500, 0.84, 25, 40),
             (470000, 1050, 30, 10000000000),
             (470000, 0.00000009, 30, 700),
             (425.33, 0.0009, 30, 700)]

result_data = [8568, 1400, 0, 4017094016600, 363300]

for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1):
    budget, exchange_rate, spread, denomination = params

    with self.subTest(f"variation #{variant}",
                      budget=budget,
                      exchange_rate=exchange_rate,
                      spread=spread,
                      denomination=denomination,
                      expected=expected):

        actual_result = exchangeable_value(budget, exchange_rate, spread, denomination)
        error_message = (f'Called exchangeable_value{budget, exchange_rate, spread, denomination}. '
                         f'The function returned {actual_result}, but '
                         f'The tests expected {expected} as the maximum '
                         f'value of the new currency .')

        self.assertEqual(actual_result, expected, msg=error_message)
Test Failure
One or more variations of this test failed. Details can be found under each [variant#].

The previous is wrong in the function:

def exchangeable_value(budget, exchange_rate, spread, denomination):
    """
    :param budget: float - the amount of your money you are planning to exchange.
    :param exchange_rate: float - the unit value of the foreign currency.
    
    :param spread: int - percentage that is taken as an exchange fee.
    :param denomination: int - the value of a single bill.
    :return: int - maximum value you can get.
    """
    # Cantidad en la divisa objetivo antes de la tarifa
    cantidad_cambio = budget * exchange_rate
    
    # Costo de la tarifa
    tarifa = cantidad_cambio * (spread / 100)
    
    # Cantidad despues de aplicar la tarifa
    cantidad_despues_tarifa = cantidad_cambio - tarifa
    
    # Numero maximo de billetes completos
    maximo_billetes = cantidad_despues_tarifa // denomination
    
    return int(maximo_billetes)

I cannot find for this function… Could you help me with that?

You want to scroll down to the next TEST FAILURE* and click on it to expand it. The variants will have much more clear results.

Code Run
test_data = [(100000, 10.61, 10, 1),
             (1500, 0.84, 25, 40),
             (470000, 1050, 30, 10000000000),
             (470000, 0.00000009, 30, 700),
             (425.33, 0.0009, 30, 700)]

result_data = [8568, 1400, 0, 4017094016600, 363300]

for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1):
    budget, exchange_rate, spread, denomination = params

    with self.subTest(f"variation #{variant}",
                      budget=budget,
                      exchange_rate=exchange_rate,
                      spread=spread,
                      denomination=denomination,
                      expected=expected):

        actual_result = exchangeable_value(budget, exchange_rate, spread, denomination)
        error_message = (f'Called exchangeable_value{budget, exchange_rate, spread, denomination}. '
                         f'The function returned {actual_result}, but '
                         f'The tests expected {expected} as the maximum '
                         f'value of the new currency .')

        self.assertEqual(actual_result, expected, msg=error_message)
Test Failure
AssertionError: 954900 != 8568 : Called exchangeable_value(100000, 10.61, 10, 1). The function returned 954900, but The tests expected 8568 as the maximum value of the new currency .

IsaacG, my problem is to make the formula to solve the problem…

Your code looks like it is mostly doing the right thing. Except you’re returning the number of the bills when you should be returning the value of the bills.

IsaacG, I changed the formulas and errors decreased, but it still continues. I don’t understand what formula to use. Can you help me with this exercise, please?

def exchangeable_value(budget, exchange_rate, spread, denomination):
    """
    :param budget: float - the amount of your money you are planning to exchange.
    :param exchange_rate: float - the unit value of the foreign currency. 
    :param spread: int - percentage that is taken as an exchange fee.
    :param denomination: int - the value of a single bill.
    :return: int - maximum value you can get.
    """
    
    # Calcular el valor unitario en tu moneda local
    valor_unit_moneda_local =  exchange_rate * denomination * (1 + spread / 100)

    # Calcular la cantidad máxima de unidades que puedes comprar con tu presupuesto
    max_valor_aceptar = budget / valor_unit_moneda_local

    return int(max_valor_aceptar)

Here an example error code…

Code Run
test_data = [(100000, 10.61, 10, 1),
             (1500, 0.84, 25, 40),
             (470000, 1050, 30, 10000000000),
             (470000, 0.00000009, 30, 700),
             (425.33, 0.0009, 30, 700)]

result_data = [8568, 1400, 0, 4017094016600, 363300]

for variant, (params, expected) in enumerate(zip(test_data, result_data), start=1):
    budget, exchange_rate, spread, denomination = params

    with self.subTest(f"variation #{variant}",
                      budget=budget,
                      exchange_rate=exchange_rate,
                      spread=spread,
                      denomination=denomination,
                      expected=expected):

        actual_result = exchangeable_value(budget, exchange_rate, spread, denomination)
        error_message = (f'Called exchangeable_value{budget, exchange_rate, spread, denomination}. '
                         f'The function returned {actual_result}, but '
                         f'The tests expected {expected} as the maximum '
                         f'value of the new currency .')

        self.assertEqual(actual_result, expected, msg=error_message)
Test Failure
AssertionError: 35 != 1400 : Called exchangeable_value(1500, 0.84, 25, 40). The function returned 35, but The tests expected 1400 as the maximum value of the new currency .

First let’s look at the error message(s).
The first one that gets displayed is not that helpful, it just tells you that “One or more variations of this test failed. Details can be found under each [variant#].”
If you unfold the next error you get a more specific error message: “AssertionError: 35 != 1400 : Called exchangeable_value(1500, 0.84, 25, 40). The function returned 35, but The tests expected 1400 as the maximum value of the new currency .”
This 35 != 1400 tells you that the actual result is far off from the expected result.


Now let’s analyze your code, line by line:

# Calcular el valor unitario en tu moneda local
# Calculate the unit value in your local currency
valor_unit_moneda_local =  exchange_rate * denomination * (1 + spread / 100)

This calculates the value of a single “foreign” bill (denomination) in your own currency, at the actual exchange rate.

Example 1 (from the instructions):
exchangeable_value(127.25, 1.20, 10, 20)
The exchange_rate is 1.20, the spread is 10, the denomination is 20.
The value of a a single 20-unit-bill (foreign currency) is 1.20 * 20 * (1 + 10 / 100) == 1.2 * 20 * 1.1 == 26.04 (your own currency).
Exchanging 26.04 units of your own money for a single 20-unit-bill sounds reasonable, it’s in the ballpark of the official exchange rate 1.20 plus 10% spread.

# Calcular la cantidad máxima de unidades que puedes comprar con tu presupuesto
# Calculate the maximum number of units you can purchase with your budget
max_valor_aceptar = budget / valor_unit_moneda_local

This calculates the number of foreign bills you can get with your own budget (a floating point value).

Example 1 (from the instructions):
exchangeable_value(127.25, 1.20, 10, 20)
The budget is 127.25, the exchange_rate is 1.20, the spread is 10, the denomination is 20.
With your budget of 127.25 you can mathematically get 127.25 / 26.04 == 4.8867... 20-unit-bills.
Again, that sounds reasonable.

return int(max_valor_aceptar)

This calculates and returns the actual whole number of bills you can with your budget by converting the floating point value max_valor_aceptar to an integer.

Example 1 (from the instructions):
exchangeable_value(127.25, 1.20, 10, 20)
The budget is 127.25, the exchange_rate is 1.20, the spread is 10, the denomination is 20.
In the previous lines you’ve calculated that you can get 4.8867 20-unit-bills, converting that to an integer gives you 4 20-unit-bills.
So the function returns 4: With those parameters you can get 4 bills.

But according to the example 1 from the instructions exchangeable_value(127.25, 1.20, 10, 20) should return 80 which is pretty far off from the actual 4.

We analyzed the function and each step looks fine, so maybe the problem is something else. What should the function calculate? What does it actually calculate?


Now please go back to @IsaacG’s previous comment:

Do you understand what he was trying to tell you?

Ok, now yes. Thanks siebenschlaefer and IsaacG. You feedback was good to understand the exercise. Thanks very much for your time.

1 Like