这是我的CS1课程的第五个项目。它比我过去的项目单调乏味,所以不幸的是我的头衔越来越差。 :(


编写一个程序,计算所有权第一年的新房年税后成本。成本是按年度
抵押成本减去节税额计算得出的。输入的应该是房屋的价格和预付款。每年的抵押贷款成本可以
估计为初始贷款余额的\ $ 3 \%\ $,用于支付
贷款本金加上初始贷款的\ $ 6 \%\ $
利益平衡。初始贷款余额是价格减去预付定金。假设边际税率为\ $ 35 \%\ $,并假定利息支付可抵扣税款。因此,节税为利息支出的\ $ 35 \%\ $
。您的程序应至少使用两个
函数定义,并应允许用户根据用户的意愿重复进行此
计算。


我可能已经欺骗了我需要的两个函数定义...

mortgage.cpp

/**
 * @file mortgage.cpp
 * @brief Computes the annual after-tax cost of a new house
 * @author syb0rg
 * @date 10/9/14
 */

#include <cctype>
#include <iostream>
#include <limits>

/**
 * Makes sure data isn't malicious, and signals user to re-enter proper data if invalid
 */
long double getSanitizedDouble()
{
    long double input = 0.0L;
    while(!(std::cin >> input) || input < 0)
    {
        // clear the error flag that was set so that future I/O operations will work correctly
        std::cin.clear();
        // skips to the next newline
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout << "Invalid input.  Please enter a positive number: ";
    }
    return input;
}

/**
 * Safetly grabs and returns a lowercase version of the character (if the lowercase exists)
 */
char32_t getSanitizedChar()
{
    // absorb newline character (if existant) from previous input
    if(std::cin.peek() == '\n') std::cin.ignore();
    return std::tolower(std::cin.get());
}

int main()
{
    do
    {
        long double housePrice = 0.0L;
        long double downPayment = 0.0L;

        // get input for house price, re-read input if not a positive number
        std::cout << "Enter the price of the house: $";
        housePrice = getSanitizedDouble();

        // get input for down payment, re-read input if not a positive number
        std::cout << "Enter the down-payment: $";
        downPayment = getSanitizedDouble();

        long double loanBalance = housePrice - downPayment;
        long double interest = .06 * loanBalance;
        long double annualMortgage = (.03 * loanBalance) + interest;
        long double savings = .35 * interest;
        long double totalCost = annualMortgage - savings;

        std::cout << "The annual after-tax cost of the house is $" << totalCost << std::endl;

        std::cout << "Run the program again (y/N): ";  // signify n as default with capital letter
    } while ('y' == getSanitizedChar());
}


评论

我知道这是家庭作业,但我仍然必须警告所有读者在处理金钱时应使用浮点数。这是一个很大的禁忌。四舍五入的错误将很快累积,金钱将会流失。 stackoverflow.com/questions/3730019/…

@EmilyL。非常像办公室的空间

@sjagr当然,Office Space中的家伙们以《超人III》为灵感:)

#1 楼

我建议进行一些较小的更改:



用符号常量替换魔术数字。当这些费率发生变化时,
修改程序会更容易。

constexpr long double ANNUAL_MORTGAGE_COST = 0.03; 
constexpr long double LOAN_PRINCIPAL_PLUS = 0.06;
constexpr long double MARGINAL_TAX_RATE = 0.35;



我建议不要将其放入函数中,而不是在main()内进行计算。

long double totalPayment(long double housePrice, long double downPayment){

    long double loanBalance = housePrice - downPayment;
    long double interest = LOAN_PRINCIPAL_PLUS * loanBalance;
    long double annualMortgage = (ANNUAL_MORTGAGE_COST * loanBalance) + interest;
    long double savings = MARGINAL_TAX_RATE * interest;
    long double totalCost = annualMortgage - savings;

    return totalCost;
}




评论


\ $ \ begingroup \ $
也许用const引用代替?仅出于效率和安全性考虑。
\ $ \ endgroup \ $
–user54356
2014年10月7日在17:28

\ $ \ begingroup \ $
@Dave通常认为内置类型足够快,可以按值传递。
\ $ \ endgroup \ $
–莫文
14-10-7在17:29

\ $ \ begingroup \ $
您已在利息和年度抵押贷款计算中切换了ANNUAL_MORTGAGE_COST和LOAN_PRINCIPAL_PLUS。如果将它们分别命名为PRINCIPAL_REDUCTION_RATE和INTEREST_RATE,这可能会更明显。
\ $ \ endgroup \ $
– Brythan
2014年10月7日17:30

\ $ \ begingroup \ $
@Brythan好抓住。
\ $ \ endgroup \ $
–user54356
2014年10月7日17:37

#2 楼

要完成已经说过的一些小事情。几乎没有一个是有意义的,但是好的实践是好的实践。



您不需要使用std::endl:它会打印换行符并刷新缓冲区,从而这里不需要。您可以简单地使用\n。这样做不会对您的程序造成影响,但这仍然是一个好习惯。

注意:正如@Emily所指出的,它仅刷新用于缓冲输入的缓冲区,情况并非如此为std::cout,除非手动将其重定向到文件。无论如何,我都会在这里保留此评论,这不是因为我仍然相信这是一种很好的做法,而是因为了解它可能仍然有用。 。没有必要在housePrice块的开头声明它们。
downPayment返回getSanitizedDouble。虽然这很好,但返回do {} while ()(返回类型为getSanitizedChar)或char32_t可能更有意义,因为您是从int的实例std::tolower读取的。
您在char中使用了错误的文字,应该是std::cin(哈哈,找到一个:p)。
也有人说这是风格问题,许多人不喜欢它,但是将大括号放在单语句std::basic_istream<char>上是个好习惯。如果每个苹果开发人员都做到了这一点,那么臭名昭著的while(!(std::cin >> input) || input < 0)漏洞就不算什么了。


评论


\ $ \ begingroup \ $
在std :: endl上使用\ n是一个样式问题,我更喜欢使用后者。在某些情况下,使用\ n可以避免代价高昂的缓冲区刷新,但我认为始终使用\ n会过早优化。更多信息:stackoverflow.com/a/25569849/2498188
\ $ \ endgroup \ $
–艾米莉·L。
2014年10月7日19:31

\ $ \ begingroup \ $
+1代表“有人说这是风格问题”-我一直在编码if(condition)doif(); else doelse();多年以来,直到最近(根据自己的意愿)才切换到if(condition){doif();} else {doelse();}-我对此很满意,主要是因为我没有键入那些括号使用IDE自动格式化/自动补全功能,同时兼顾两种解决方案的优点(安全性+少键入)-尽管我可以说,经过激烈的编辑后,剩下的花括号让整个代码的格式搞砸了,这有点恼人。
\ $ \ endgroup \ $
–user20300
2014年10月8日13:47

#3 楼

你确实被骗了。出于一个问题的考虑,使函数能够计算总成本更加合理:

double total_cost(double balance);


至少您可以重用它长达数年的总成本。来。