Quantcast
Channel: User Peter - Reinstate Monica - Stack Overflow
Viewing all articles
Browse latest Browse all 223

Answer by Peter - Reinstate Monica for Compute for the income tax to be paid based on the given salary

$
0
0

Here is an elaborate program with the following features:

  • Accepts income of up to ca. 1.8 * 1013 units (Rupees, Dollars etc).
  • Computes cent-exact.
  • Accepts data from the command line or stdin.
  • Prompts when stdin is a terminal.
  • Handles input errors.
  • Even on a terminal one can simply paste space multiple separated numbers,no need to have one per line (6th input prompt below).

Maybe some things apart from the actual algorithm are useful here:

  • Use a return type which can communicate errors (struct ParseResult).
  • Use the return value of scanf and other input functions to detect input errors, and distinguish it from end-of-file.
  • Move similar-looking code into parametrized functions instead of duplicating it (MakeParseResult() makes ParseIncomeInHundredthsFromString() and ParseIncomeInHundredthsFromStream() both small).
  • Some algorithms are well-suited for recursion, like this one (computeTaxes()).
  • Separate input from processing (computeTaxes() knows nothing about I/O).
  • Like in Allan's answer, do not hard-wire data in the code (the taxSteps array could be read from somewhere).
  • Pay attention to value ranges (32 bits are not enough for big incomes, let alone in cent or Rupees).
  • Use the proper conversion specifiers in printf() and scanf(), here: PRIu64 and SCNu64. It's somewhat cumbersome but necessary for portability. Different implementations have different native data types for the uint.._t typedefs, and thus need different conversion specifiers (what's %ul on Linux is %ull on Windows, for example).
  • Even though it is not standard C, some common Posix functions like isatty() are available in non-Posix implementations as well. They are useful.

Sample sessions:

$ gcc -Wall -o income-tax income-tax.c && ./income-tax.exeTax brackets:0.00 .. 1000.00: 2.00%1000.00 .. 3000.00: 7.00%Above: 11.00%Please input income values in a format like '12345.99 ...'1000.00Taxes for 1000.00: 20.00Please input income values in a format like '12345.99 ...'3000.00Taxes for 3000.00: 160.00Please input income values in a format like '12345.99 ...'10000.00Taxes for 10000.00: 930.00Please input income values in a format like '12345.99 ...'10000.10Taxes for 10000.10: 930.01Please input income values in a format like '12345.99 ...'1234.56 7890.89 121212121212.12Taxes for 1234.56: 36.41Please input income values in a format like '12345.99 ...'Taxes for 7890.89: 697.99Please input income values in a format like '12345.99 ...'Taxes for 121212121212.12: 13333333163.33Please input income values in a format like '12345.99 ...'$

From command line and per pipe:

$ ./income-tax.exe 1500.00 4500.25 1234567890123.00Taxes for 1500.00: 55.00Taxes for 4500.25: 325.02Taxes for 1234567890123.00: 135802467743.53$ echo "1500.00 4500.25 1234567890123.00" | ./income-tax.exeTaxes for 1500.00: 55.00Taxes for 4500.25: 325.02Taxes for 1234567890123.00: 135802467743.53
//*************************************************// A tax computing program for a multi-step tax bracket.// The brackets are specified in the taxSteps array.// The program is currency agnostic but assumes a // "unit" and "hundredths" (Dollar/Cent, Euro/Cent, Pound/Penny).// It stores money values in those "hundredths" (e.g. Cents) // using 64 bit integers. (32 bit would not quite be enough// for the highest earners; Elon Musk payed $11bn in 2021.)// The tax rate is likewise stored in 1/100s of a percent// to facilitate non-integer tax rates.// All arithmetics are integer; resulting taxes are rounded down.//// The program accepts input as commandline arguments // ("income-tax 1234.56 777.88") or from standard input// ("echo 1234.56 777.88 | income-tax").// Iff standard input is a terminal it issues a prompt.#include <stdio.h>#include <stdint.h> // for 64 bit type#include <assert.h>#include <limits.h> // uint64_max#include <inttypes.h>#include <stdlib.h> // exit#ifdef _MSC_VER // microsoft compiler, as opposed to *nix environment#   define _CRT_SECURE_NO_WARNINGS // silence MSVC#   pragma warning(disable : 4996) // MSVC prefers _isatty#   include<io.h>#else#   include <unistd.h>#endif// Convenience function because of the unwieldy format strings.// Prints "a string like "123.45" from 12345.void printHundredths(uint64_t Hundredths){    printf("%" PRIu64 ".%02" PRIu64, Hundredths / 100, Hundredths % 100);}/// A single tax step: An interval in centi-money units with a rate in "centipercent".struct TaxStep{    uint64_t StepSizeInHundredths;    unsigned int TaxRateInHundredthPercent;};uint64_t computeTaxesInHundredthsForStep(uint64_t incomeInHundredths, struct TaxStep taxStep){     uint64_t taxedInThisStep         = incomeInHundredths < taxStep.StepSizeInHundredths         ? incomeInHundredths         : taxStep.StepSizeInHundredths;    // Such a high income would overflow in the expression below and compute     // a tax amount that's much too low. The threshold, for 100% tax, is     // > 1.8E15 Hundredths, or 1.8E13 whatever (dollars, rupees). In rupees    // we get close to a realistic income (one rupee ~ 1 cent), 1.8E12,     // 1.8 trillion dollars. If, say, Elon Musk liquidates its entire    // stock at the zenith of his wealth, in Rupees or Lira, we could come close.     // Let's say that's OK for now.    if (    taxStep.TaxRateInHundredthPercent != 0&&  taxedInThisStep > UINT64_MAX / taxStep.TaxRateInHundredthPercent)    {        fprintf(stderr, "Income ");        printHundredths(incomeInHundredths);        fprintf(stderr, " exceeds value range.\nMax permissible : ");        printHundredths(UINT64_MAX / taxStep.TaxRateInHundredthPercent);        exit(2);    }    // taxableMoney * HundredthsPercent is precise     // (and won't overflow, we asserted that above).    // The division is exact to the cent, rounded down (we are a nice tax office).    // The rate is in "centipercent", so we must then divide by 100*100.    // With percent: "money*11/100" with "centipercent": "money*1100/10000".    return (taxedInThisStep * taxStep.TaxRateInHundredthPercent) / 10000;}/// <summary>/// Step through the tax bracket and apply the tax rate to each/// step. The steps are interval sizes, not absolute values./// </summary>/// <param name="incomeInHundredth">The income in cents or whatever</param>/// <param name="taxSteps">The first element in an array of tax steps which have/// an interval size and a rate for that interval.</param>/// <returns></returns>uint64_t computeTaxes(uint64_t incomeInHundredth, struct TaxStep* taxSteps){    // The function simply calls itself with the remaining money    // and the remaining tax brackets. Because the last interval is    // UINT_MAX, incomeInHundredth <= taxSteps->StepSizeInHundredths    // always triggers for the last interval, stopping the recursion.    return computeTaxesInHundredthsForStep(incomeInHundredth, *taxSteps)+ (   incomeInHundredth <= taxSteps->StepSizeInHundredths             ? 0             : computeTaxes(incomeInHundredth - taxSteps->StepSizeInHundredths, taxSteps+1)          );}// A convenience function.void errExit(const char* msg){    fprintf(stderr, msg);    exit(1); // indicates error}/// <summary>/// Communicates the result of a parsing attempt. EOI is "end of information"./// </summary>enum ParseDiagE { ParseDiag_ERR, ParseDiag_EOI, ParseDiag_OK };/// <summary>/// A 64 return value which also carries an indicator whether/// the value could be set properly from the input./// </summary>struct ParseResult{    uint64_t parsedValue;    enum ParseDiagE parseDiag;};/// <summary>/// Factored out the common logic of the two parse methods below./// Sets the ret.parseDiag member appropriately, depending on the scanf diagnostic/// return value (which indicates the number of parsed items and should be 2)./// If the diag value is OK, combines the two numbers before and after the dot/// to set ret.parsedValue,/// </summary>/// <returns>the result structure</returns>struct ParseResult MakeParseResult(uint64_t incomeInInUnits, uint64_t IncomeFractionInHundredths, int scanfDiag){    struct ParseResult ret = { 0, ParseDiag_OK };    switch (scanfDiag)    {    case EOF:        // typically OK: End of string, or end of file/pipe closed.        ret.parseDiag = ParseDiag_EOI;        break;    case 0:    case 1:        // bad input: scanf should have read 2.        ret.parseDiag = ParseDiag_ERR;        break;    }    if (IncomeFractionInHundredths > 99)    {        // Could be parsed, but too many "cents", e.g. 1.234        ret.parseDiag = ParseDiag_ERR;    }    if (ret.parseDiag == ParseDiag_OK)    {        // only if everything is OK, actually compute anything.        ret.parsedValue = incomeInInUnits * 100 + IncomeFractionInHundredths;    }    return ret;}/// <summary>/// Expects a number in the English float format [0-9]+\.[0-9]+/// </summary>/// <returns></returns>struct ParseResult ParseIncomeInHundredthsFromString(const char* input){    uint64_t incomeInInUnits = 0, IncomeFractionInHundredths = 0;    int diag = sscanf(input, "%" SCNu64 ".%" SCNu64, &incomeInInUnits, &IncomeFractionInHundredths);    return MakeParseResult(incomeInInUnits, IncomeFractionInHundredths, diag);}/// <summary>/// Expects a number in the English float format [0-9]+\.[0-9]+/// Output a prompt only if asked (do not spam sdout for batch runs)./// </summary>/// <returns></returns>struct ParseResult ParseIncomeInHundredthsFromStream(FILE *stream, int prompt){    if (prompt)    {        printf("Please input income values in a format like '12345.99 ...'\n");    }    uint64_t incomeInInUnits = 0, IncomeFractionInHundredths = 0;    int diag = fscanf(stream, "%" SCNu64 ".%" SCNu64, &incomeInInUnits, &IncomeFractionInHundredths);    return MakeParseResult(incomeInInUnits, IncomeFractionInHundredths, diag);}void PrintTaxBrackets(struct TaxStep *steps){    uint64_t overallIncomeInHundredths = 0;    printf("Tax brackets:\n");    while(1)    {        if (steps->StepSizeInHundredths == UINT64_MAX)        {             printf("Above: ");            printHundredths(steps->TaxRateInHundredthPercent);            printf("%%\n");            break;        }        else        {            printHundredths(overallIncomeInHundredths);            printf(" .. ");            printHundredths(overallIncomeInHundredths += steps->StepSizeInHundredths);            printf(": ");            printHundredths(steps->TaxRateInHundredthPercent);            printf("%%\n");++steps;        }    }}int main(int argc, char** argv){    // The specification of the tax brackets: A succession of intervals    // with their respective tax rate, in "centipercent" (1120 would be 11.20%).    // The last step **must** be of size UINT64_MAX (i.e., the remaining income),    // that's how the program recognizes it's the last step    struct TaxStep taxSteps[] = { {1000 * 100, 2 * 100}, {2000 * 100, 7 * 100}, {UINT64_MAX, 11 * 100 } };    // If we have command line arguments we should process those.    int ShouldProcessArgv = argc > 1;    // If stdin is a terminal    int inpIsFromTerminal = isatty(fileno(stdin));    // spam stdout only for interactive sessions.    if (!ShouldProcessArgv && inpIsFromTerminal)    {        PrintTaxBrackets(taxSteps);    }    /// Command line argument index. argv[0] is the program name,    /// so we start with index 1 for the first actual argument.    int argi = 1;     // loop through text command line arguments or textual numbers    // from stdin.    do    {        // Iff there are no command line arguments, we check standard input.        // Apart from the input source, the processing is the same.        struct ParseResult res = ShouldProcessArgv            ? ParseIncomeInHundredthsFromString(argv[argi])            : ParseIncomeInHundredthsFromStream(stdin, inpIsFromTerminal);        if (res.parseDiag == ParseDiag_ERR)        {            errExit("Input format error\n");        }        else if (res.parseDiag == ParseDiag_EOI)        {            break;        }        printf("Taxes for ");        printHundredths(res.parsedValue);        printf(": ");        printHundredths(computeTaxes(res.parsedValue, taxSteps));        printf("\n");    } while (ShouldProcessArgv ? ++argi < argc : 1);    return 0;}

Viewing all articles
Browse latest Browse all 223

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>