Sčítanie ľubovoľne veľkých čísel v C # .NET
Napadlo vás niekedy, ako by sa sčítavali číslo väčšie ako dátové typy? Trebárs takých 80 miliárd alebo ešte viac? V tomto prípade môžeme použiť dátovú štruktúru BIGINT, ktorý reprezentuje nekonečne veľké číslo.
My si za účelom precvičovanie skúsime použiť metódu LSS na ukladanie čísel ako jednotlivé cifry. Túto metódu v praxi nepoužívajte, je len precvičenie programovanie a myslenia.
Veľké prirodzené číslo budeme v programe reprezentovať ako zoznam. Napr .: 879653 by v zozname vyzeralo takto: 8; 7; 9; 6; 5; 3
V tutoriále si nielen precvičíme používanie Listu <>, cyklov a parsovanie, ale tiež StreamReader a to preto, že program bude načítať čísla z textového súboru. Tak sa poriadne pripútajte a ideme na to!
Najskôr musíme pridať menný priestor pre prácu so súbormi System.IO. IO znamená Input-Output. Náš kód by mal vyzerať nejako takto:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO;
Vďaka tomuto riadku budeme môcť používať napríklad StreamReader pre načítanie textových súborov alebo napríklad StreamWriter pre ich zápis.
Aby kód vyzeral prehľadnejšie, vytvoríme metódu pre načítanie čísel zo súboru a druhú metódu pre sčítaní čísel a následný výpis. V metóde Main iba zavoláme tieto metódy.
1) Príprava
Než začneme, deklarujeme si nejaké premenné mimo metódu Main, aby sa nachádzali v triednom odbore platnosti
static List<int> cislo1 = new List<int>(); static List<int> cislo2 = new List<int>(); static List<int> vysledek = new List<int>();
List je vlastne dynamické pole (počet jeho prvkov nie je pevný) a keďže nevieme o aké veľké číslo pôjde, je to asi najjednoduchšie voľba.
Ďalej si vytvoríme v počítači obyčajný textový súbor a napíšeme do neho dve čísla, každé na iný riadok.
2) Načítanie zo súboru
Vytvoríme si statickú metódu načíta (), ktorá nemá žiadny parameter.
static void Nacti() { }
Vnútri metódy vytvoríme blok pre prácu so súbormi:
using(StreamReader sr = new Streamreader(***)); { }
Using označuje vnorený blok v ktorom používame StreamReader. Medzi jeho zloženými zátvorkami je kód, v ktorom načítame súbory. Po ukončení kódu medzi zátvorkami sa StreamReader ukončí.
*** - cesta k súboru s textom, napr .: @ "C: \ temp \ text.txt"
Zavináč nám vo stringu "vypína" escape sekvencie. Ak by sme ho nechceli použiť, museli by sme miesto každého \ napísať \\.
Do bloku using vložíme nasledujúci kód, ktorý si hneď vysvetlíme:
//Pomocná proměnná int c; //Cyklus načítá do cislo1 dokud nenarazí na konec řádku nebo souboru while ((c = sr.Read()) != 13 && c != -1) { //Převod na hodnotu (ne ASCII) c = (int)Char.GetNumericValue((char)c); //Přidání do seznamu cislo1.Add(c); } //Přeskočení hodnoty 10 sr.Read(); //Cyklus totožný s prvním, ale načítá do cislo2 while ((c = sr.Read()) != 13 && c != -1) { c = (int)Char.GetNumericValue((char)c); cislo2.Add(c); }
c je pomocná premenná, do ktorej zapisujeme hodnotu prečítaného znaku (hodnoty sú z ASCII tabuľky).
Nasleduje cyklus while, ktorý prebieha tak dlho, ako platí podmienka.
Do c priradíme znak, potom sa opýtame, či sa c nerovná 13 (na konci riadku sú vždy 2 netlačiteľné znaky a to: 13 10) alebo -1 (sr.Read () vracia -1 ak sa dostane na koniec súboru).
Teraz nám však nastáva problém. Premenná c je celé číslo a my celé číslo potrebujeme, ale toto celé číslo neukazuje hodnotu, ale číslo znaku v tabuľke ASCII.
Preto musíme na premennú c Přetypování na char použiť metódu Char.GetNumericValue (), ktorý nám vráti hodnotu čísla a tú až potom pretypovať na int. Viem, že to pre niekoho môže znieť zložito, ale ak sa nad tým zamyslíte, vezmete si papier a ceruzku a načrtneme si to, uvidíte, že je to veľmi jednoduché.
A teraz nám už len zostáva zapísať číslo do zoznamu.
Po prebehnutí prvého cyklu je celé číslo zapísané v zozname znak po znaku a cyklus narazí na číslo 13 (čo je znak konca riadku), ktoré nezapíše a ukončí sa.
sr.Read (); nám prečíta ďalší znak a to 10, ktorú chceme iba preskočiť a tak ju nikam nezapisujú.
Nakoniec ešte opakujeme rovnaký cyklus, jenom zapisujeme číslo2.
3) Sčítanie
Vytvoríme si statickú metódu Sect ():
static void Secti() { //Rozdíl v počtu prvků jednotlivých polí int rozdil = Math.Abs(cislo1.Count - cislo2.Count); //Přidávání 0 na začátek if (cislo1.Count > cislo2.Count) { for (int j = 0; j < rozdil; j++) { cislo2.Insert(0, 0); } } //Přidávání 0 na začátek else if (cislo2.Count > cislo1.Count) { for (int j = 0; j < rozdil; j++) { cislo1.Insert(0, 0); } } //Zápis do stringů (jenom kvůli výpisu) string c1 = string.Join("", cislo1); string c2 = string.Join("", cislo2); //Výpis Console.WriteLine("{0,60}",c1.TrimStart('0')); Console.WriteLine("{0,60}",c2.TrimStart('0')); for (int i = 0; i < 65; i++) Console.Write("="); //Výpočet výsledku int zbytek = 0; List<int> vysledek = new List<int>(); //cyklus sčítající jednotlivé prvky a přičítající zbytek for (int i = 1; i <= cislo1.Count; i++) { //Sečte čísla nad sebou a přidá zbytek int cislo = cislo1[cislo1.Count - i] + cislo2[cislo2.Count - i] + zbytek; //Zbytek je vynulován zbytek = 0; //Při sčítání dvou jednociferných čísel nemůžeme dostat číslo větší než 18, //proto nemusíme řešit zbytek větší než 1 if (cislo >= 10) { zbytek = 1; cislo -= 10; } //Vložení čísla na začátek seznamu vysledek.Insert(0, cislo); } //Pokud při posledním číslu by byl zbytek, napíše ho jako první if (zbytek != 0) { vysledek.Insert(0, zbytek); } //Výpis výsledku string vys = string.Join("", vysledek); Console.WriteLine("\n{0,60}",vys); }
Vytvoríme si premennú rozdil, do ktorej zapíšeme absolútnu hodnotu rozdielu počtu prvkov v oboch číslach.
Napr. 125 - 3 cifry, 22568 - 5 cifier, rozdiel = | 3-5 | = 2
Urobili sme to preto, aby sme vedeli koľko 0 pred ktoré číslo prirobiť. Chceme obidva zoznamy rovnako dlhé, aby sme ich prechádzali jedným jednoduchým cyklom.
Nasledujú 2 podmienky pre zistenie kratšieho zoznamu a doplnenie 0 na jeho začiatok.
Následne vytvoríme dve premenné typu string a zapíšeme do nich zoznam pomocou metódy string.Join (), oddeľovač nastavíme na prázdny znak, pretože chceme číslo v jednom kuse.
Reťazce vypíšeme zarovnané na 60 miest (kvôli veľkým číslam)
Potom napíšeme veľké množstvo "=" pre vytvorenie deliace čiary na obrazovke.
Nasleduje asi nejzáživnější časť a tou je výpočet. Vytvoríme si premennú pre zapisovanie zvyšku a nový zoznam pre výsledok.
Postup počítania je dostatočne popísaný v kóde a tak zrovna preskočíme do metódy Main (), čím sa chýlíme ku koncu.
V metóde Main jenom jednoducho zavoláme metódy a potom použijeme Console.ReadLine (), nech sa nám program sám neukončí.
static void Main(string[] args) { Nacti(); Secti(); Console.ReadLine(); }
Teraz stačí len spustiť a uvidíte, ako ste túto lekciu zvládli
Ak by boli nejaké otázky, napíšte do komentárov alebo správu.
PS. Pre precvičenie si môžete program skúsiť prepísať pre načítanie čísel zo vstupu alebo napríklad vytvoriť násobenie.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 108x (33.88 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C#