Ciszę w pracach wypełniała muza:https://www.youtube.com/watch?v=HrXCW11Wifc
Płacąc rachunki czasami zdarza mi się uważniej przyjrzeć blankietowi na przelew. Taki dokument zawiera kwotę do zapłaty (zawsze uważam, że za dużą, ale to mój punkt widzenia i z pewnością „strona przeciwna” nie podziela tej opinii ). A poważnie, to … by zminimalizować lub uniemożliwić jakiekolwiek manipulacje, kwota powinna być wyrażona w postaci słownej. Jednak na wydrukowanym blankiecie przelewu nie znajduję wydrukowanej kwoty słownie tylko wydrukowane jedynie cyfry i to w dodatku w formie skróconej.
Tak zastanawiam się nad przyczyną takiego stanu rzeczy. Czy to wynika z lenistwa twórców oprogramowania? Sam kiedyś tworząc przeróżne oprogramowanie natknąłem się na podobną problematykę. Wygrzebałem więc z signumowego archiwum fragment oprogramowania, którego zadaniem jest wyrażenie kwoty w formie słownej. Algorytm pochodzi z okresu połowy lat dziewięćdziesiątych ubiegłego wieku. Zadałem sobie tylko trochę trudu by wyrazić go w języku C (w oryginale jest napisany w języku MODULA 2) i umieścić go w realiach mikrokontrolera AVR. Może komuś się przyda, więc będzie jak znalazł (adaptacja do realiów maszyn w architekturze innej niż Harvard wymaga kosmetycznych zmian).
Algorytm poprawnie, w sensie języka polskiego, generuje końcówki wyrazów. Jakby dokładniej się przyjrzeć gramatyce polskiej, to można dostrzec, że jest podobne jak „Kali liczyć: jeden, dwa, dużo”. Jest podobnie, tylko występuje szerszy zakres (a dokładniej, granice są w innych miejscach). Na przykładzie złotych, to poprawnie brzmi:
- jeden złoty,
- dwa złote,
- trzy złote,
- cztery złote,
- pięć złotych.
- jeden milion,
- dwa, trzy, cztery miliony,
- pięć, sześć, siedem, osiem, dziewięć milionów.
Kod: Zaznacz cały
#define Zero 0
#define Jeden 1
#define Kilka 2
#define Duzo 3
- Zero – oznacza, że nie wystąpiła żadna aktywna konwersja i służy do eliminacji takich przypadków jak: zero milionów zero tysięcy … (brzmi to trochę pokracznie),
- Jeden – oznacza konieczność dodania „mnożnika” w wariancie jeden (przykładowo jeden milion),
- Kilka – oznacza konieczność dodania „mnożnika” w wariancie kilka (dokładnie w zakresie 2..4: przykładowo 3 miliony),
- Duzo – oznacza koniecznośc dodania „Mnożnika” w wariancie dużo (dokładnie w zakresie 5..9: przykładowo 6 milionów).
Kod: Zaznacz cały
static uint8_t Liczba3CyfrowaNaNapis ( uint8_t * Napis ,
uint16_t Liczba )
{
uint16_t Cyfra100 ; /* cyfra setek */
uint16_t Cyfra10 ; /* cyfra dziesiated */
uint16_t Cyfra1 ; /* cyfra jednosci */
/*-------------------------------------------------------------------------*/
* Napis = 0 ;
if ( Liczba == 0 )
{
return ( Zero ) ;
} /* if */ ;
Cyfra100 = Liczba / 100 ;
Liczba = Liczba % 100 ;
Cyfra10 = Liczba / 10 ;
Cyfra1 = Liczba % 10 ;
if ( Cyfra100 != 0 )
{
StrCpyFlash ( Napis , ( uint16_t ) Setki [ Cyfra100 ] ) ;
} /* if */ ;
if ( ( Cyfra10 == 1 ) & ( Cyfra1 != 0 ) )
{
AppendFlash ( Napis , ( uint16_t ) Nascie [ Cyfra1 ] ) ;
return ( Duzo ) ;
} /* if */ ;
if ( Cyfra10 != 0 )
{
AppendFlash ( Napis , ( uint16_t ) Dziesiatki [ Cyfra10 ] ) ;
} /* if */ ;
if ( Cyfra1 != 0 )
{
AppendFlash ( Napis , ( uint16_t ) Jednostki [ Cyfra1 ] ) ;
} /* if */ ;
switch ( Cyfra1 )
{
case 0 :
return ( Duzo ) ;
case 1 :
if ( ( Cyfra100 == 0 ) & ( Cyfra10 == 0 ) )
return ( Jeden ) ;
else
return ( Duzo ) ;
case 2 :
case 3 :
case 4 :
if ( Cyfra10 != 1 )
return ( Kilka ) ;
else
return ( Duzo ) ;
case 5 :
case 6 :
case 7 :
case 8 :
case 9 :
return ( Duzo ) ;
default :
return ( Zero ) ;
} /* switch */ ;
} /* Liczba3CyfrowaNaNapis */
Główna funkcja konwersji wydziela z kwoty grosze (posiłkuje się stałą C02 → 102), najmłodsza 3-cyfrowa część liczby (posiłkuje się stałą C05 → 105), kolejna 3-cyfrowa część jest wydzielana za pomocą stałej C08 → 108 oraz najbardziej znacząca część liczby wydzielona za pomocą stałej C1011 → 1011.
Funkcja ma następująca postać:
Kod: Zaznacz cały
void Slownie ( uint64_t Kwota ,
uint8_t * Napis )
{
uint16_t CzescLiczby ;
uint8_t LokalnyNapis [ 63 ] ;
uint8_t Zakres ;
uint8_t OstatniZakres ;
/*-------------------------------------------------------------------------*/
* Napis = 0 ;
OstatniZakres = 0xFF ;
/* miliardy */
CzescLiczby = ( uint16_t ) ( Kwota / C1011 ) ; /* 10 ** 11 */
Kwota = Kwota % C1011 ; /* 10 ** 11 */
Zakres = Liczba3CyfrowaNaNapis ( Napis , CzescLiczby ) ;
if ( Zakres != Zero )
{
OstatniZakres = Duzo ;
switch ( Zakres )
{
case Jeden :
AppendFlash ( Napis, ( uint16_t ) Miliard ) ;
break ;
case Kilka :
AppendFlash ( Napis, ( uint16_t ) Miliardy ) ;
break ;
case Duzo :
AppendFlash ( Napis, ( uint16_t ) Miliardow ) ;
} /* switch */ ;
} /* if */ ;
/* miliony */
CzescLiczby = ( uint16_t ) ( Kwota / C108 ) ; /* 10 ** 8 */
Kwota = Kwota % C108 ; /* 10 ** 8 */
Zakres = Liczba3CyfrowaNaNapis ( LokalnyNapis , CzescLiczby ) ;
if ( Zakres != Zero )
{
OstatniZakres = Duzo ;
Append ( Napis , LokalnyNapis ) ;
switch ( Zakres )
{
case Jeden :
AppendFlash ( Napis, ( uint16_t ) Milion ) ;
break ;
case Kilka :
AppendFlash ( Napis, ( uint16_t ) Miliony ) ;
break ;
case Duzo :
AppendFlash ( Napis, ( uint16_t ) Milionow ) ;
} /* switch */ ;
} /* if */ ;
/* tysiace */
CzescLiczby = ( uint16_t ) ( Kwota / C105 ) ; /* 10 ** 5 */
Kwota = Kwota % C105 ; /* 10 ** 5 */
Zakres = Liczba3CyfrowaNaNapis ( LokalnyNapis , CzescLiczby ) ;
if ( Zakres != Zero )
{
OstatniZakres = Duzo ;
Append ( Napis , LokalnyNapis ) ;
switch ( Zakres )
{
case Jeden :
AppendFlash ( Napis, ( uint16_t ) Tysiac ) ;
break ;
case Kilka :
AppendFlash ( Napis, ( uint16_t ) Tysiace ) ;
break ;
case Duzo :
AppendFlash ( Napis, ( uint16_t ) Tysiecy ) ;
} /* switch */ ;
} /* if */ ;
/* zlote */
CzescLiczby = ( uint16_t ) ( Kwota / C102 ) ; /* 10 ** 2 */
Kwota = Kwota % C102 ; /* 10 ** 2 */
Zakres = Liczba3CyfrowaNaNapis ( LokalnyNapis , CzescLiczby ) ;
if ( Zakres != Zero )
{
Append ( Napis , LokalnyNapis ) ;
OstatniZakres = Zakres ;
} /* if */ ;
if ( OstatniZakres != 0xFF )
{
switch ( OstatniZakres )
{
case Jeden :
AppendFlash ( Napis, ( uint16_t ) Zloty ) ;
break ;
case Kilka :
AppendFlash ( Napis, ( uint16_t ) Zlote ) ;
break ;
case Duzo :
AppendFlash ( Napis, ( uint16_t ) Zlotych ) ;
} /* switch */ ;
} /* if */ ;
/* grosze */
CzescLiczby = ( uint16_t ) Kwota ;
Zakres = Liczba3CyfrowaNaNapis ( LokalnyNapis , CzescLiczby ) ;
Append ( Napis , LokalnyNapis ) ;
switch ( Zakres )
{
case Zero :
AppendFlash ( Napis, ( uint16_t ) Jednostki [ 0 ] ) ;
AppendFlash ( Napis, ( uint16_t ) Groszy ) ;
break ;
case Jeden :
AppendFlash ( Napis, ( uint16_t ) Grosz ) ;
break ;
case Kilka :
AppendFlash ( Napis, ( uint16_t ) Grosze ) ;
break ;
case Duzo :
AppendFlash ( Napis, ( uint16_t ) Groszy ) ;
} /* switch */ ;
} /* Slownie */
Program ten pozwala poprzez łącze szeregowe wprowadzić znakowo liczbę, która zostaje przetworzona na postać słowną i wysłana w kanał szeregowy.
Łącząc się z programem poprzez dowolny emulator terminala mamy:
Czesc koles z http://www.microgeek.eu:
Wprowadz jakas liczbe (w groszach) i walnij na koniec Enter
0
zero groszy
1
jeden grosz
2
dwa grosze
3
trzy grosze
4
cztery grosze
5
piec groszy
6
szesc groszy
7
siedem groszy
8
osiem groszy
9
dziewiec groszy
10
dziesiec groszy
11
jedenascie groszy
12
dwanascie groszy
20
dwadziescia groszy
21
dwadziescia jeden groszy
22
dwadziescia dwa grosze
23
dwadziescia trzy grosze
50
piecdziesiat groszy
99
dziewiecdziesiat dziewiec groszy
100
jeden zloty zero groszy
101
jeden zloty jeden grosz
123
jeden zloty dwadziescia trzy grosze
1234
dwanascie zlotych trzydziesci cztery grosze
12345
sto dwadziescia trzy zlote czterdziesci piec groszy
123456
jeden tysiac dwiescie trzydziesci cztery zlote piecdziesiat szesc groszy
1234567
dwanascie tysiecy trzysta czterdziesci piec zlotych szescdziesiat siedem groszy
12345678
sto dwadziescia trzy tysiace czterysta piecdziesiat szesc zlotych siedemdziesiat osiem groszy
123456789
jeden milion dwiescie trzydziesci cztery tysiace piecset szescdziesiat siedem zlotych osiemdziesiat dziewiec groszy
1234567890
dwanascie milionow trzysta czterdziesci piec tysiecy szescset siedemdziesiat osiem zlotych dziewiecdziesiat groszy
12345678901
sto dwadziescia trzy miliony czterysta piecdziesiat szesc tysiecy siedemset osiemdziesiat dziewiec zlotych jeden grosz
123456789012
jeden miliard dwiescie trzydziesci cztery miliony piecset szescdziesiat siedem tysiecy osiemset dziewiecdziesiat zlotych dwanascie groszy
1234567890123
dwanascie miliardow trzysta czterdziesci piec milionow szescset siedemdziesiat osiem tysiecy dziewiecset jeden zlotych dwadziescia trzy grosze
12345678901234
sto dwadziescia trzy miliardy czterysta piecdziesiat szesc milionow siedemset osiemdziesiat dziewiec tysiecy dwanascie zlotych trzydziesci cztery grosze
Załącznik, przykładowy program: