Konwerter liczby na zapis słowny - optymalizacja kodu (lub bardziej recenzja)

0

No dzień dobry.

Jestem nowy na tym forum, więc witam serdecznie.
Miałem długą przerwę w programowaniu, więc w ramach przypomnienia postanowiłem zrobić coś bardzo prostego, czyli właśnie rzeczony konwerter.
I zwracam się z prośbą, czy można ten kod jakoś bardziej zoptymalizować:

#include <iostream>
#include <string>
#include <vector>

const std::string digits[] = {
    "",
    "jeden",
    "dwa",
    "trzy",
    "cztery",
    "piec",
    "szesc",
    "siedem",
    "osiem",
    "dziewiec"
};
const std::string dozens[] = {
    " ",
    " ",
    "dwadziescia",
    "trzydziesci",
    "czterdziesci",
    "piecdziesiat",
    "szescdziesiat",
    "siedemdziesiat",
    "osiemdziesiat",
    "dziewiecdziesiat",
};

const std::string hundreds[] = {
    "",
    "sto",
    "dwiescie",
    "trzysta",
    "czterysta",
    "piecset",
    "szescset",
    "siedemset",
    "osiemset",
    "dziewiecset" 
};

const std::string fromTenToNineteen[] = {
    "dziesiec",
    "jedenascie",
    "dwanascie",
    "trzynascie",
    "czternascie",
    "pietnascie",
    "szescnascie",
    "siedemnascie",
    "osiemnascie",
    "dziewiectnascie"
};

std::string convertNumberToString(int number)
{
    std::string converted_number;
    if(number == 0) 
        return "zero";
    if(number < 0) 
    {
        converted_number += "minus ";
        number *= -1;
    }
    if(number >= 1000)
    {
        switch(number / 1000)
        {
            case 1: converted_number += "tysiac "; break;
            ////////////////
            case 2:
            case 3:
            case 4: converted_number += digits[number / 1000] + " tysiace "; break;
            ////////////////
            case 5: 
            case 6:
            case 7:
            case 8:
            case 9: converted_number += digits[number / 1000] + " tysiecy "; break;   
        }
    }
    if(number % 1000 >= 100)
        converted_number += hundreds[number / 100 % 10] + " ";
    if(number % 100 >= 20)
        converted_number += dozens[number / 10 % 10] + " ";
    if((number % 100 >= 10) && (number % 100 < 20))
        return converted_number += fromTenToNineteen[number % 10];
    return converted_number += digits[number % 10];
}

int main()
{
    int number;
    std::cout << "> ";
    std::cin >> number;
    if(std::cin.fail())
    {
        std::cout << "Invalid input\n";
        return EXIT_FAILURE;
    }
    if((number <= -10000) || (number >= 10000))
    {
        std::cout << "Number must be in range from -9999 to 9999\n";
        return EXIT_FAILURE;
    }
    std::cout << convertNumberToString(number) << "\n";
    std::cin.ignore();
    std::cin.get();
}


Dziękuję za pomoc i pozdrawiam ogółem.

2

Tu nie ma co optymalizować. Jedyne możesz zrobić mikro-optymalizacje. Np użyć std::string_view, mienić prototyp funkcji:

std::ostream& toWordRep(std::ostream& out, int value);

Bardziej bym polecał spróbować czegoś takiego:
https://godbolt.org/z/WxzWvc

1

czy można ten kod jakoś bardziej zoptymalizować

Można napisać to w nowszym standardzie ( nie testowałem dokładnie ).

#include <iostream>
#include <map>

// C++17

using namespace std;

using llint = long long int;

const map<llint,string> name
{
  {0,"zero"},{1,"jeden"},{2,"dwa"},{3,"trzy"},{4,"cztery"},
  {5,"piec"},{6,"szesc"},{7,"siedem"},{8,"osiem"},{9,"dziewiec"},
  {10,"dziesiec"},{11,"jedenascie"},{12,"dwanascie"},{13,"trzynascie"},{14,"czternascie"},
  {15,"pietnascie"},{16,"szesnascie"},{17,"siedemnascie"},{18,"osiemnasie"},{19,"dziewietnasie"},
  {20,"dwadziescia"},{30,"trzydziesci"},{40,"czterdziesci"},{50,"piedziesiat"},{60,"szescdziesiat"},
  {70,"siedemdziesiat"},{80,"osiemdziesiat"},{90,"dziewiecdziesiat"},{100,"sto"},{200,"dwiescie"},
  {300,"trzysta"},{400,"czterysta"},{500,"piecset"},{600,"szescset"},{700,"siedemset"},{800,"osiemset"},
  {900,"dziewieset"},{1000,"tys."},{1000000,"mln."},{1000000000,"mld."},{1000000000000,"bln."}
};

const map<int,llint> ratio
{
  {4,1000},{5,1000},{6,1000},
  {7,1000000},{8,1000000},{9,1000000},
  {10,1000000000},{11,1000000000},{12,1000000000},
  {13,1000000000000},{14,1000000000000},{15,1000000000000}
};

class Number
{

public:

    Number( llint value_ ): value {value_} {}

    friend ostream& operator<<( ostream& out , const Number& number )
    {
        out << number.resolve();
        return out;
    }

private:

    llint value;
    const string prefix { value<0?"minus "s:""s };

    llint f1( llint factor ) const { return abs(value)/factor; }
    llint f2( llint factor ) const { return f1(factor)*factor; }
    llint f3( llint factor ) const { return abs(value) - f2(factor); }
    string partial_name( llint factor ) const
    {
        string result { Number{f1(factor)}.resolve() + " " + name.at(factor) };
        return f3(factor)!=0 ? result + " " + Number{f3(factor)}.resolve() : result;
    }

    string resolve() const
    {
        return prefix+[this]( int size ){
                       if( size < 3 ) return abs(value)<21 ? name.at(abs(value)) : name.at(f2(10)) + " "+ name.at(f3(10));
                       else if( size == 3 ) return name.at(f2(100)) + " " + Number{f3(100)}.resolve();
                       else
                       {
                           auto iter {ratio.find(size)};
                           return partial_name( iter!=cend(ratio) ? iter->second : crbegin(ratio)->second );
                       }
                     }( to_string(abs(value)).size() );
    }
};

enum class as { text };

struct Tag
{
    Tag( ostream& s_ ): s{s_} {};
    ostream& s;
};

Tag operator<<( ostream& out , as ){ return Tag{out}; };

ostream& operator<<( Tag tag , llint number )
{
    tag.s << Number{number};
    return tag.s;
};

int main()
{
    int number1 { -223 };
    int number2 { 32322222 };

    cout << Number{number2} << endl;
    cout << as::text << 0 << endl;
    cout << as::text << number1 << endl;
    cout << as::text << -12 << endl;
    cout << as::text << 1000 << endl;
    cout << as::text << 1266298 << endl;
    cout << as::text << -628165298 << endl;
    cout << as::text << -1654621111110 << endl;

    return 0;
}

https://godbolt.org/z/PPr63v

1 użytkowników online, w tym zalogowanych: 0, gości: 1